string array is not properly projected when passing with ajax - c#

Using ajax I want to pass 2 objects: string[] and Options to my controller. The problem is that every time string[] in controller scope is set to null.
Thats js code:
$("#exportCsv").click(function () {
var checkboxes = $('.TableChBox:checkbox:checked');
var allIds = [];
for (var i = 0, n = checkboxes.length; i < n; ++i) {
var el = checkboxes[i];
if (el.id) {
allIds.push(el.id);
}
}
console.log(allIds); // it prints ["RId1604678", "RId1604679"]
var form = $('#SearchForm').serialize();
$.ajax({
url: '#Url.Action("ExportToCsv", "Bank")',
type: 'POST',
data: JSON.stringify({
ids: allIds,
options: form
}),
dataType: 'json',
error: function (xhr) {
alert('Error: ' + xhr.statusText);
},
async: true,
});
});
And thats c# code:
public void ExportToCsv(string[] ids, Options options)
{
// ids is null here
// options is not null
}
When I use debugger I can see, that options is successfully filled, but ids is null. Why does that happen?
Edit 1
As someone suggested I should Add contentType. So I added:
url: '#Url.Action("ExportToCsv", "Bank")',
type: 'POST',
contentType: "application/json; charset=utf-8",
And still - ids is not null, but options is.
Edit 2
Someone suggested to change two parameters in function to one. So I changed my code to:
part of controller
public class ExportModel
{
[JsonProperty(PropertyName = "one")]
public string One { get; set; }
[JsonProperty(PropertyName = "two")]
public string Two { get; set; }
}
[System.Web.Mvc.HttpPost]
public void ExportToCsv([System.Web.Http.FromBody] ExportModel model)
{
//model.One is null
//model.Two is null
}
part of js code
data: JSON.stringify({
one: "foo",
two: "bar"
}),
And even with that simple example with two strings it is not working.

In your controller method you should declare it as accepting a model like so:
public void ExportToCsv(ExportModel model)
{
}
And then define your model like so:
public class ExportModel
{
[JsonProperty(PropertyName = "ids")]
public string[] Ids {get;set;}
[JsonProperty(PropertyName = "options")]
public Options Options {get;set;}
}
As patilprashant6792 pointed out, your ajax request is missing the content type, so you should replace it with this:
$("#exportCsv").click(function () {
var checkboxes = $('.TableChBox:checkbox:checked');
var allIds = [];
for (var i = 0, n = checkboxes.length; i < n; ++i) {
var el = checkboxes[i];
if (el.id) {
allIds.push(el.id);
}
}
console.log(allIds); // it prints ["RId1604678", "RId1604679"]
var form = $('#SearchForm').serialize();
$.ajax({
url: '#Url.Action("ExportToCsv", "Bank")',
type: 'POST',
data: JSON.stringify({
ids: allIds,
options: form
}),
contentType: 'application/json',
dataType: 'json',
error: function (xhr) {
alert('Error: ' + xhr.statusText);
},
async: true,
});
});
If you don't declare the content type, it will default to application/x-www-form-urlencoded; charset=UTF-8

You should use list of string instead of array & try.
public List<string> Ids {get;set;}

Related

Posting array from Ajax to cshtml.cs using .NET Core

I am using .NET Core and I am attempting to send an array from the .cshtml page via Ajax to the corresponding method. I have a strongly typed class that I wish the array to bind to but when the method is called, it returns null. I have managed to send simple data back (e.g. a single string) but anything like an array and it returns null.
This is the Ajax call and the array I am trying to send through.
var miniPediPrice = document.getElementById("MiniPedi").value * 1500;
var miniPediDuration = parseFloat('#Model.miniPedi.Duration');
const products = [{
Name: '#Model.miniPedi.Name',
Price: miniPediPrice.toString(),
Duration: miniPediDuration.toString(),
GelPolish: "false",
NailArt: "false"
}]
console.log(products);
const total = 0;
try {
$.ajax({
dataType: 'json',
type: 'POST',
url: "/Products?handler=CalculatePrice",
traditional: true,
data: JSON.stringify(products),
//data: JSON.stringify({ products: products }),
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function (data) {
console.log(data);
$("#totalPrice").val(data)
},
});
} catch (e) {
}
The method that the ajax calls. The "products" is always null.
public IActionResult OnPostCalculatePrice([FromBody] List<Products> products)
{
var totalPrice = "";// product.Name;
//TotalPrice = "£" + (totalPrice / 100).ToString();
return new JsonResult(totalPrice);
}
Model class for Products:
public class Products
{
public string Name { get; set; }
public decimal Price { get; set; }
public decimal Duration { get; set; }
public bool GelPolish { get; set; }
public bool NailArt { get; set; }
public Products(string productName, decimal productPrice, decimal productDuration, bool gelPolish, bool nailArt)
{
Name = productName;
Price = productPrice;
Duration = productDuration;
GelPolish = gelPolish;
NailArt = nailArt;
}
}
I have searched high and low for how to fix this but no luck. I am new to jQuery/Javascript so I am still learning syntax etc. I hope the information posted is enough.
You can do following steps to make it work.
1:Remove the constructor from your produst.
2:Change your ajax like(add contentType: "application/json" and decimal,bool type no need to convert to string):
var products =
[{
Name: "assad",
Price: 12.5,
Duration:4.5,
GelPolish: false,
NailArt: false
}];
$.ajax({
dataType: 'json',
contentType: "application/json",
type: 'POST',
url: "/Products?handler=CalculatePrice",
traditional: true,
data: JSON.stringify(products),
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function (data) {
console.log(data);
$("#totalPrice").val(data)
},
});
3:Your action:
public IActionResult OnPostCalculatePrice([FromBody] List<Products> products)
{
var totalPrice = "";// product.Name;
//TotalPrice = "£" + (totalPrice / 100).ToString();
return new JsonResult(totalPrice);
}
Test result:
Can you
Add 'contentType':'application/json'; in your ajax call.
Don't do JSON.stringfy.Directly use the products in data.
Remove the constructor from Products.cs class (It should be Product
sinceyou are passing the array list to denote products)
Assign Price,duration decimal value and GelPoslish, NailArt boolean value (boolean without quotes.)
.

Link HTML site with MVC site's Action

I'm building a HTML page on button click, it will transfer data from localStorage at HTML page to MVC site's action and process action then save data at MVC site
this is my HTML button 's function:
function OH10() {
var url1 = "#Url.Action('createFuel','FuelExtras')";
debugger;
for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i);
var val = localStorage.getItem(key);
$.ajax({
type: "POST",
url: url1,
data: val,
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () {
alert("Data has been added successfully.");
},
error: function () {
alert("Error while inserting data");
}
});
}
};
And MVC site 's action:
[HttpPost]
[System.Web.Services.WebMethod]
public ActionResult createFuel(FuelExtra fuelExtra)
{
db.FuelExtras.Add(fuelExtra);
db.SaveChanges();
string message = "SUCCESS";
return Json(new { Message = message, JsonRequestBehavior.AllowGet });
}
Any Suggestions guys?
And 1 more question is right now in development, I've build 2 sites in same Solution, but when I deploy it to intranet i have to separate it into 2 sites. Is it ok?
I found several mistakes in your example:
1) System.Web.Services.WebMethod only used in webforms, it cannot be used for ActionResult in MVC and should be removed.
2) The AJAX callback placed inside a loop, therefore it will execute multiple times instead of single request.
3) The passed data is the last localStorage value taken from getItem() function as single string, not a key-value pair reflecting model property names and their values.
Hence, by assuming you have this model:
public class FuelExtra
{
public string CaptainEmpNo { get; set; }
public string AirCraft { get; set; }
public string FlightNo { get; set; }
public string DepartureAirport { get; set; }
public string ArrivalAirport { get; set; }
// other properties
}
Then you should send key-value pair object as JSON string because the contentType setting has been set to application/json by JSON.stringify(), as in example below:
function OH10() {
var key = []; // array of keys
var val = []; // array of values
var obj = {}; // combined KVP object
var url1 = "#Url.Action("CreateFuel", "FuelExtras")";
debugger;
for (var i = 0; i < localStorage.length; i++) {
key.push(localStorage.key(i));
val.push(localStorage.getItem(key));
}
for (var n = 0; n < key.length; n++) {
obj[key[n]] = val[n]; // create KVP object from both arrays
}
$.ajax({
type: "POST",
url: url1,
data: JSON.stringify({ fuelExtra: obj }), // convert KVP object to JSON string
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (result) {
alert("Data has been added successfully.");
},
error: function (xhr, status, err) {
alert("Error while inserting data");
}
});
};
And the controller action should be like this:
[HttpPost]
public ActionResult CreateFuel(FuelExtra fuelExtra)
{
db.FuelExtras.Add(fuelExtra);
db.SaveChanges();
return Json(new { Message = "SUCCESS" });
}
Since you're sending AJAX request as POST method, then JsonRequestBehavior.AllowGet is unnecessary.
Note:
Make sure all key names inside passed JSON string from AJAX is the same as all property names declared inside FuelExtra class.

How to map Mvc View model and ajax post data which have list property?

I have a MVC controller action with inputModel parameter which have list type property and , I ,m using $('form').serialize() to serialize the form content and append some of my custom data to serialized string, but inside the action method input model object the list property is empty,
Can any one help me , below is the code samples
My controller
[HttpPost]
public ActionResult Edit(ALDS.Web.Areas.Direct2M3.Models.ItemInputModel collection)
{ }
ItemInputModel class
public class ItemInputModel
{
//......Some property here..
public List<FabricCompositionInputModel> FabricCompositions { get; set; }
}
FabricCompositionInputModel class
public class FabricCompositionInputModel
{
public int ItemID { get; set; }
public string CompositionCode { get; set; }
public decimal Value { get; set; }
}
Ajax call
function save() {
var compositionData = generateCompositionForSave(); //Returns array
var data = $('form').serialize();
var d2 = JSON.stringify(compositionData);
var data2 = data + '&FabricCompositions=' + d2;
$.ajax({
type: 'POST',
dataType: 'json' ,
cache: false,
url: '/ItemMaster/Edit',
data: data2,
success: function (data, textStatus, jqXHR) {
sucess(data);
},
error: function (jqXHR, textStatus, errorThrown) {
failed(jqXHR);
}
});
}
Array generating function
function generateCompositionForSave() {
var arr = [];
var delClassList = $('#compositionContainer').find('.btnRemoveCompositions');
for (var c = 0; c < delClassList.length; c++) {
var row = $(delClassList[c]).closest('.row');
var code = row.find('.compositionCode').val();
var value = parseInt(row.find('.compositionValue').val());
arr.push({ItemID:0, CompositionCode:code, Value:value});
}
return arr;
}
Your not building the data correctly, and it needs to be
var compositionData = generateCompositionForSave();
var data = $('form').serializeObject(); // see function below
data['FabricCompositions'] = compositionData; // add the array to the serialized data
var data2 = JSON.stringify({ collection: data }), // stringify it
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8", // add contentType
dataType: 'json' ,
cache: false,
url: '#Url.Action("Edit", "ItemMaster")', // don't hard code your url's
data: data2,
success: function (data, textStatus, jqXHR) {
....
And add the following function (warning: this will not work correctly for a <select multiple> element)
$.fn.serializeObject = function () {
var o = {};
var a = this.serializeArray();
$.each(a, function () {
if (o[this.name] === undefined) {
o[this.name] = this.value || '';
}
});
return o;
};
Note that if you generate your form controls correctly using a for loop or custom EditorTemplate for typeof FabricCompositionInputModel (refer Post an HTML Table to ADO.NET DataTable), for example
for(int i = 0; i < Model.FabricCompositions.Count; i++)
{
#Html.TextBoxFor(m => m.FabricCompositions[i].CompositionCode)
#Html.TextBoxFor(m => m.FabricCompositions[i].Value)
}
then all that is required is
var data = $('form').serialize();
$.ajax({
type: 'POST',
dataType: 'json' ,
cache: false,
url: '#Url.Action("Edit", "ItemMaster")',
data: data,
success: function (data, textStatus, jqXHR) {

pass value to controller by using ajax

I want to pass value from view to controller by using ajax.
<button onclick="addCommentByAjax()" >Save</button>
My script:
function addCommentByAjax() {
$.ajax({
type: "POST",
url: '/Survey/DoDetailSurvey',
data: {
choiceId: "1"
}
});
}
Controller:
[HttpPost]
public ActionResult DoDetailSurvey(SurveyViewModel model, string choiceId)
{
//
}
but choiceId always null
Change couple of things.
First assign an id or class to your button.Second remove inline onclick function and use ajax click function.Then specify the request type as Post.
$('#btnComment').click(function () {
var choiceId = $('#YourChoiceId').val();
$.ajax({
url: '/Survey/DoDetailSurvey',
data: { 'choiceId' : choiceId},
type: "post",
cache: false,
success: function (response) {
//do something with response
},
error: function (xhr, ajaxOptions, thrownError) {
alert('error occured');
}
});
});
Then your controller should look like this
[HttpPost]
public ActionResult DoDetailSurvey(string choiceId)
{
//
}
I don't know how you are populating your viewmodel,so I purposely removed them and shown an working example.
In case you want to pass viewmodel you should construct your data object like this:
var data = {};
data.Property1 = some val;
data.Property2 = "some val";
$.post('/Survey/DoDetailSurvey', data);
Sample structure of SurveyViewModel I assume:
public class SurveyViewModel
{
public int Property1 { get; set; }
public string Property2 { get; set; }
}
Since there are two parameter in your controller, you need to identify them both form the client side. Further, you should specify the contentType.
You spread the payload like so:
function addCommentByAjax() {
var payload = {
model: {
// whatever properties you might have
},
choiceId: 1
};
$.ajax({
type: "POST",
url: '/Survey/DoDetailSurvey',
contentType: 'application/json',
data: JSON.stringify(payLoad)
});
}
function addCommentByAjax() {
$.ajax({
type: "POST",
url: '/Survey/DoDetailSurvey?choiceId=1'
}
});
}
You can also pass like this
or for more parameters
function addCommentByAjax() {
$.ajax({
type: "POST",
url: '/Survey/DoDetailSurvey?choiceId=1&Name=Arun'
}
});
}

JS Array is not received by c# webapi

I have a test js function that should post data to webapi by Post method
function test() {
var puffs = [];
var puffObject = {
id: "2735943",
priority: "1"
};
puffs.push(puffObject);
puffs.push(puffObject);
var dto =
{
po: puffs
};
$.ajax({
type: "POST",
url: "../api/PuffPriority/",
contentType: "application/json; charset=utf-8",
data: JSON.stringify(dto),
dataType: "json",
success: function (data, status) {
if (data) {
console.log("Welcome");
} else {
console.log("No data");
}
},
error: function (error) {
console.log("Error");
}
});
}
In the controller class i have
public void Post(PuffPriority[] po){
//Do something here with po, but po is always empty
}
where PuffPriority Model is
public class PuffPriority
{
public string id { get; set; }
public string priority { get; set; }
}
I dont know whats wrong , the values are sent by JS but api Controller don't fetch it :( Please help, i have already wasted a lot of time.
You have a bug in your code.
Simply change
url: "../api/PuffPriority/"
to
url: "../api/Post/"
or change your method name from Post to PuffPriority
Changed
public void Post(PuffPriority[] po){
//Do something here with po, but po is always empty
}
To
[FromBody]List<PuffPriority> po{
//Do something here with po, but po is always empty
}

Categories

Resources