Having trouble passing complex model to controller through ajax call - javascript

I'm trying to update my model whenever a button is clicked. When I log the data I'm sending in the razor file to the console, the data is all there. However, when the controller method is called, the model is empty.
My onclick method:
function addCoupon() {
var code = document.getElementById("coupon-entry").value;
$.ajax({ // Validate coupon first. This is working.
method: "post",
url: `/cart/validate-coupon/` + code,
contentType: "application/json; charset=utf-8"
}).done(result => {
if (result.success) {
var model = #Html.Raw(Json.Serialize(Model));
console.log(model); // Countries and CheckoutData are correct here
$.ajax({
method: "post",
url: `/cart/add-coupon/` + code,
contentType: "application/json; charset=utf-8",
data: model
}).done(result => {
console.log("It worked");
});
}
});
}
My model:
public bool IsPos { get; set; }
public List<CountryDto> Countries { get; set; }
public CheckoutData CheckoutData { get; set; }
public string Payment ProcessorError { get; set; }
public bool DisplayRequiredErrors { get; set; }
public List<string> ValidationErrors { get; set; } = new List<string>();
public PaymentInformationModel PaymentInformation { get; set; } = new PaymentInformationModel();
public bool UseSavedCard { get; set; }
My controller:
[HttpPost("add-coupon/{code}")]
public async Task<IActionResult> AddCouponAsync(string code, CheckoutModel model)
{
// Countries and CheckoutData are null here
}
There were several similar questions posted on here, but they all either had simple models, or had solutions that didn't work for me when I tried them.
Thanks!

You should try changing it to this (otherwise it isn't valid javascript):
(Notice that it needs to be encapsulated in '')
var model = '#Html.Raw(Json.Serialize(Model))';

Related

Ajax Post (Model binded) passing null to the controller

I am making an AJAX POST request to the controller (ASP.NET Core MVC), yet the value for the parameter is coming through as null. I tried several solutions given on StackOverflow. But, I couldn't correct it. Please help.
My view collects class fees information. There may have more than one payment.
$(function () {
$('#sendSlip').click(function (e) {
e.preventDefault();
let fees = new Array(); //To store payment info
let tb = $('#feesTable:eq(0) tbody');
//Collecting info of each payment
tb.find("tr").each(function () {
let row = $(this);
let fee = {};
if (row.find('input:checkbox:first').is(':checked')) {
fee.ClassId = row.find("TD").eq(0).html();
fee.FeeId = row.find("TD").eq(1).html();
fee.Amount = row.find(".fee").html();
fee.Month = row.find(".month").html();
fees.push(fee);
}
});
//Arranging data to send to controller
var data = {
fees: fees,
Bank: $(".bank").val(),
PaidAmount : $(".amount").val(),
PaidDate : $(".date").val()
};
console.log(data);
$.ajax({
type: 'POST',
url: '#Url.Action("StudentPayment_Create", "StudentPayment")',
contentType: "application/json",
headers: { 'RequestVerificationToken': gettoken() },
data: //{ data: JSON.stringify(data) },
JSON.stringify(data) ,
})
});
});
Model
public class StudentPaymentSlipVM
{
public StudentPaymentPaidClassVM fees { get; set; }
public string Bank { get; set; }
public DateTime PaidDate { get; set; }
public int PaidAmount { get; set; }
}
Controller
public ActionResult StudentPayment_Create([FromBody] List<StudentPaymentSlipVM> data)
{
---
}
Object details at runtime
From your attached screenshot for data to be passed to the controller, the data's structure was unmatched with the data model the controller expected.
Assume the data structure for the front-end is correct.
Controller should expect that the received data is a StudentPaymentSlipVM object. While in the StudentPaymentSlipVM object, the fees is a StudentPaymentPaidClassVM array.
Model
public class StudentPaymentSlipVM
{
public List<StudentPaymentPaidClassVM> fees { get; set; }
public string Bank { get; set; }
public DateTime PaidDate { get; set; }
public int PaidAmount { get; set; }
}
Controller
public ActionResult StudentPayment_Create([FromBody] StudentPaymentSlipVM data)
{
}
While from your JQuery part, make sure that your data object to be passed to API must be matched with the data type as your model in the back-end.
var data = {
fees: fees,
Bank: $(".bank").val(),
PaidAmount : parseInt($(".amount").val()),
PaidDate : $(".date").val()
};
I tried to pass my data to controller by binding to a ViewModel (StudentPaymentSlipVM) which has all required definitions. But I couldn't do it. So I changed the way and pass my object to Controller as following way now it is working.
And also I would like to thanks Yong Shun.
Changed the JQuery code
$.ajax({
type: 'POST',
url: '#Url.Action("action", "controller")',
headers: { 'RequestVerificationToken': gettoken() },
data: dataObj,
})
I changed the Controller
[HttpPost]
public ActionResult StudentPayment_Create(List<StudentPaymentPaidClassVM> Fees, string Bank, decimal PaidAmount, DateTime PaidDate)
{
.....
}

Autofill Textbox based on DropDownList

MVC 4 Changing multiple display fields based on DropDownListFor selection
I'm trying to follow the above example but I think I'm having problems either with my javascript or my controller.
JavaScript in View
$('#InstitutionDDL').change(function () {
var institutionID = $(this).val();
$.ajax({
type: 'POST',
url: '/Compendia/FillImplementationInfo?InstitutionID=' + institutionID,
dataType: 'json',
contentType: 'application/json',
data: { InstitutionID: institutionID },
success: function (ret) {
$('#RegionImplementedField').val(ret.implementedRegion);
$('#ProvinceImplementedField').val(ret.implementedProvince);
$('#DistrictImplementedField').val(ret.implementedDistrict);
$('#LocationImplementedField').val(ret.implementedLocation);
},
error: function (ex) {
}
});
return false;
});
Controller Action
[HttpGet]
public JsonResult FillImplementationInfo(int InstitutionID)
{
var ret = (from e in db.Institutions
where e.ID == InstitutionID
select new
{
implementedRegion = e.Province.Region.RegionName,
implementedProvince = e.Province.ProvinceName,
implementedDistrict = e.District,
implementedLocation = e.InstitutionAdress
}).FirstOrDefault();
return Json(ret, JsonRequestBehavior.AllowGet);
}
Source of DropDownList in View
<div class="form-group">
#Html.LabelFor(model => model.InstitutionID, "Institution", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(m => m.InstitutionID, new SelectList(""), "--Select Institution--", htmlAttributes: new { #class = "form-control", #id ="InstitutionDDL" })
#Html.ValidationMessageFor(model => model.InstitutionID, "", new { #class = "text-danger" })
</div>
</div>
^from which after selecting, I want to pull all related data from connected tables using InstitutionID and put it in their respective textboxes known with IDs ending in #ImplementedField
Debugging Results
After selecting an option from the DropDownList, my script could capture the institutionID up to $.ajax({ data: { InstitutionID: institutionID }. However, it skips the success: function(ret) entirely and goes straight to return false; . Furthermore, the error that is being returned is 500 Internal Server Error, and based on the debugger, ret is being treated everywhere as undefined. I've already tried modifying my controller and/or javascript multiple times but with no success. If I'm having a problem with my linq statement, I'm also posting here my Models. Apologies in advance for the long post, I really have no idea where I went wrong.
Models
public class Compendium
{
public int ID { get; set; }
public int InstitutionID { get; set; }
public string RegionImplemented { get; set; }
public string ProvinceImplemented { get; set; }
public string DistrictImplemented { get; set; }
public string LocationImplemented { get; set; }
public virtual Institution Institution { get; set; }
}
public class Institution
{
public int ID { get; set; }
public int ProvinceID { get; set; }
public District? District { get; set; } //enum
public virtual ICollection<Compendium> Compendia { get; set; }
public virtual Province Province { get; set; }
}
public class Province
{
public int ID { get; set; }
public int RegionID { get; set; }
public virtual Region Region { get; set; }
public string ProvinceName { get; set; }
public virtual ICollection<Institution> Institutions { get; set; }
}
First, this URL pattern with query string is not correct to initiate an AJAX call:
url: '/Compendia/FillImplementationInfo?InstitutionID=' + institutionID,
You need to change int Url.Action or simply remove query string on it:
url: '/Compendia/FillImplementationInfo',
// or
url: '#Url.Action("FillImplementationInfo", "Compendia")'
and then remove contentType: 'application/json' since the return type already declared as JSON with dataType: 'json'.
Second, as a general convention, the HTTP method used by jQuery AJAX call & the controller action method must be match to send the argument data successfully. In view side the AJAX call sent as POST method:
$.ajax({
type: 'POST',
...
});
But the action method uses HTTP GET, which causes AJAX call cannot reach the action method since it only accepts GET request:
[HttpGet]
public JsonResult FillImplementationInfo(int InstitutionID)
{
...
}
Note that you can use either GET or POST method with AJAX call, but ensure both of them are matched each other. Here is an example below:
View (jQuery AJAX)
$.ajax({
type: 'GET', // ensure this HTTP method same as used by controller action method
...
});
Controller
[HttpGet]
public JsonResult FillImplementationInfo(int InstitutionID)
{
...
}

Form Data not serialized in asp.net core mvc controller model

C# model class
public class SubCategoryTwoViewModel
{
public long Id { get; set; }
public string SubCatTwoName { get; set; }
public CategoryViewModel Category { get; set; }
public SubCategoryOneViewModel SubCatOne { get; set; }
public string PictureUrl { get; set; }
public List<IFormFile> File { get; set; }
public UserViewModel AddedBy { get; set; }
public DateTime AddedOn { get; set; }
public UserViewModel Updated_By { get; set; }
public DateTime? UpdatedOn { get; set; }
public bool Active { get; set; }
}
Here is the CategoryViewModel
public class CategoryViewModel
{
public long CategoryId { get; set; }
}
Here is the controller method
[HttpPost]
public JsonResult AddEditSubCategoryTwo(SubCategoryTwoViewModel model)
{
}
Here is the ajax call which use the Form Data to serialized the data send to the controller method.
var ajaxUrl = ApplicationRootUrl("AddEditSubCategoryTwo", "Category");
var formData = new FormData();
var totalFiles = document.getElementById("subCatFile").files.length;
for (var i = 0; i < totalFiles; i++) {
var file = document.getElementById("subCatFile").files[i];
formData.append("File", file);
}
formData.append('SubCatTwoName', self.subCatTwoName());
var category = {
CategoryId: self.selectCategory()
};
formData.append('Category', category);
var subCatOne= {
SubCategoryOneId: self.selectCategorytwo()
};
formData.append('SubCatOne', subCatOne);
formData.append('Active', self.active());
$.ajax({
type: "POST",
contentType: false,
processData: false,
url: ajaxUrl,
data: formData,
dataType: "json",
success: function (data) {
}
});
I,am getting some field data in the controller but the java script value is not serialized to the controller model.
Here is the screenshot of the sample
In the screen shot I am getting the Category & SubCatOne field as null. But active, SubCatTwoName and File field has receive the value. I want to get Category & SubCatOne value in the controller model object. How can I achieved this.
Trying to add the object directly will not work. Instead you can make use of model binding by adding the nested fields with the correct name (separate the property hierarchy with dots). e.g.
formData.append('Category.CategoryId', self.selectCategory());

Http post method seen as http get method

I have this javascript snippet :
$.ajax({
type: "Post",
contentType: 'application/json',
url: "../api/Pointage/GetPointages",
data: JSON.stringify({
laDate: DateConsultation,
lstcols: Collaborators,
lEquipe: equipe,
Type: 3,
}),
success: function (data) {
console.log(data);
call3(data);
}
});
the signature of the service method is the following :
[HttpPost]
public List<ItemStatistiquesPointageMonth> GetPointages(Nullable<System.DateTime> laDate = null, List<Collaborateur> lstcols =null, Nullable<int> lEquipe = null, int Type = -1)
When I make the call, the serive is unreachable !!
So what is the reason of this problem ? How can I fix it?
Create a model class which reflect the object you create in the client
public class dataModel
{
public Nullable<System.DateTime> laDate { get; set; }
public List<Collaborateur> lstcols { get; set; }
public Nullable<int> lEquipe { get; set; }
public int Type { get; set; }
}
And then add it to the method with the FromBody attribute
[HttpPost]
public List<ItemStatistiquesPointageMonth> GetPointages([FromBody] dataModel data){}
Create a Model with your paramaters and pass it to your post method
[HttpPost]
public List<ItemStatistiquesPointageMonth> GetPointages([FromBody] MyModel model)
also use dataType: "json"

Ajax not receiving complete JsonResult

Background:
In the view, we ask (via jquery and ajax) the controller for data from the database. The data is returned as Json, but for reasons unknown one part of the Json object is returned as null, even though it is properly set in the controller's JsonResult.
The Code:
The class to be returned as JsonResult
public class InData
{
public InData() { }
public AppsWithActions[] apps { get; set; }
public User[] users { get; set; }
public string timePeriod { get; set; }
public string startDate { get; set; }
public string endDate { get; set; }
public string dataType { get; set; }
}
The Problem is the string arrays actionIds and actionNames in the following class are null in the javascript, even though they have the correct values in the JsonResult:
public class AppsWithActions
{
public AppsWithActions() { }
public string id { get; set; }
public string name { get; set; }
public string[] actionIds { get; set; }
public string[] actionNames { get; set; }
}
The controller function that sets the InData and returns it to the javascript:
//Takes a goal setting, turns it to indata and returns a JsonResult
public JsonResult GetIndataFromGoalSettingId(SettingId settingId)
{
var id = ToGuid(settingId.idString);
GoalSetting setting = Session.Query<GoalSetting>()
.Where(x => x.Id == id)
.FirstOrDefault();
var indata = TransformGoalSettingToInData(setting);
return Json(new { returnvalue = indata }, JsonRequestBehavior.AllowGet);
}
The ajax call that returns everything correct, except the apps.actionIds and apps.actionNames
function getIndataFromGoalSettingId(settingId) {
if (settingId != null) {
settingIdIn = { "idString": settingId};
$.ajax({
type: "POST",
async: false,
traditional: true,
url: 'GetIndataFromGoalSettingId',
data: JSON.stringify(settingIdIn),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (result) {
//...
}
});
}
}
It should be said that we have successfully used the same kind of infrastructure for getting data and returning it as Json to the javascript before, but if anyone has a better suggestion feel free to spell it out!

Categories

Resources