Passing array of object from Ajax function to web service - javascript

I have two arrays of same object type that I am passing to a web service API. I look at the array just before it is passed to web service and each has an object in it. I put a breakpoint in API and the list is empty. Can't figure out what I am doing wrong.
I defined a DTO as:
public class AdminDTO
{
public string fn { get; set; }
public string mi { get; set; }
public string ln { get; set; }
public string email { get; set; }
public string userid{ get; set; }
}
in JS function I populate two arrays as such:
// this is done inside a foreach loop
var fn = userData.FirstName;
var mi = userData.Initial;
var ln = userData.LastName;
var email = userData.Email;
var userid = userData.UserID;
//push the object onto the array
admins.push({
"fn": fn,
"mi": mi,
"ln": ln,
"email": email,
"userid": userid
});
...
...
// clone admin list for later comparison
currAdmins = admins.slice(0);
At some point "admins" is changed through user interaction. Some objects are removed and some new ones are added. I use below to get two new arrays to hold the differences between "admins" and "currAdmins":
var adminsChanged = $(admins).not(currAdmins).length > 0 || $(currAdmins).not(admins).length > 0;
var adminsToAdd = [];
var adminsToRemove = [];
if (adminsChanged) {
adminsToAdd = $(admins).not(currAdmins);
adminsToRemove = $(currAdmins).not(admins);
}
...
// "newMapping" is a mapping of another DTO called "projctDTO", this is passed correctly to web service
doUpdate(newMapping, "projDTO", adminsToRemove, adminsToAdd);;
Now, I am trying to pass these two arrays to web serive via ajax call. They both have objects in them:
function doUpdate(mapping, jsonObjName, adminsToAdd, adminsToRemove) {debugger
$.ajax({
url: "../WebService/Blah.asmx/updateSomething",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{" + jsonObjName + ":" + JSON.stringify(mapping) + ", adminRemoveDTO: " + JSON.stringify(adminsToRemove) + ", adminAddDTO:" + JSON.stringify(adminsToAdd) + " }",
}).done(function (result) {debugger
...
});
Web service API:
public string UpdateSomething(ProjectDTO projDTO, List<AdminDTO> adminRemoveDTO, List<AdminDTO> adminAddDTO)
{
// projDTO has stuff in it but both lists are empty
....
}
I also tried calling ajax function and setting ajax data like this, but didn't work:
doUpdate(newMapping, "projDTO", adminsToRemove, "adminRemoveDTO", adminsToAdd, "adminAddDTO");
...
function doUpdate(mapping, jsonObjName, adminsToAdd, jsonObjNameAR, adminsToRemove, jsonObjNameAA) {debugger
$.ajax({
url: "../WebService/AIR.asmx/updateProject",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
data: "{" + jsonObjName + ":" + JSON.stringify(mapping) + ", " + jsonObjNameAR + ":" + JSON.stringify(adminsToRemove) + ", " + jsonObjNameAA + ":" + JSON.stringify(adminsToAdd) + " }",
Update
For testing purpose, instead of using the array that (supposedly) contains the differences to pass as parameters, I used the original arrays: "admins" and "currAdmins" and it worked. This tells me the problem is with the array resulting from the ".not" operation.
Also, when I examined the result of the ",not" operation I noticed not only it has the difference between two arrays but also an entry called "prevObject" that contains the initial set of objects. I hoe this helps in someone suggesting a solution.

You are correct in that the $(a).not(b) is not doing what you want here. jQuery's not does not do arrays. Here is how you could implement a function to create a new array that excludes all items from a that are also in b:
function filterNotIn(a, b, keySelector) {
const keysFromB = new Set(b.map(keySelector));
return a.filter(item => !keysFromB.has(keySelector(item)));
}
adminsToAdd = filterNotIn(admins, currAdmins, admin => admin.userid);

Related

Ajax call: Invalid web service call, missing value for parameter: 'itemTypes'

I have created an ajax call and am trying to send an object as an argument to the server but I am getting the following error:
Invalid web service call, missing value for parameter: 'itemTypes'
I have checked the itemTypes variable in javascript and it contains the expected values:
sessionStorage.itemTypeUid = "18"
sessionStorage.itemTypeName = "TABLE_NAME"
args = {CurId: 18, BaseTableName: "TABLE_NAME"}
javascript:
var itemTypes = {
CurId: parseInt(sessionStorage.itemTypeUid),
BaseTableName: sessionStorage.itemTypeName
};
aj("DeleteItem", itemTypes);
Ajax:
function aj(funcName, args) {
retval = $.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: 'ItemEdit.asmx/' + funcName,
data: JSON.stringify(args),
dataType: "json",
error: function (a, b, c) {
var errors = a + b + c
}
});
}
VB:
<WebMethod()>
Public Sub DeleteItem(itemTypes As Object)
Dim CurId = ""
Dim BaseTableName = ""
actions.DeleteItem(CurId, BaseTableName)
End Sub
You can update your web method like:
<WebMethod()>
Public Sub DeleteItem(CurId As Integer, BaseTableName As String)
actions.DeleteItem(CurId, BaseTableName)
End Sub
Please make sure parameter name here is exactly the same as the values passed in the ajax call. Even if the name is the same but the casing is different, then you might get errors. So, please double-check the variable names first. Also, remove
Dim CurId = ""
Dim BaseTableName = ""
from the method, so that there are no name conflicts.

How to read serialized data (sent through Jquery POST) in MVC collection

I have a form and one submit button click, i serialize my form and send it to MVC action.
Jquery code
var formCollection = $('form').serialize();
var path = $(this).attr('data-content-url');
// check if no more error
$.ajax({
type: 'POST',
url: path,
cache: false,
data: { collection: formCollection },
datatype: 'json',
success: function (data) {
// do stuff
}
});
MVC side
[HttpPost]
public ActionResult MethodName( FormCollection collection )
{
}
i do get serialize data in my collection variable as
name=test&id=1 as collection[0]
How can i break this collection[0] so that this name and id can be assigned directly to class parameter, something like
Person p = new person { collection["name"], collection["id"] }
Many thanks
this worked, create a new helper class which convert your serialized data in formcollection as you would normally expect
private FormCollection DeSerialize(FormCollection form)
{
FormCollection collection = new FormCollection();
//un-encode, and add spaces back in
string querystring = Uri.UnescapeDataString(form[0]).Replace("+", " ");
var split = querystring.Split(new [] {'&'}, StringSplitOptions.RemoveEmptyEntries);
Dictionary<string, string> items = new Dictionary<string, string>();
foreach (string s in split)
{
string text = s.Substring(0, s.IndexOf("="));
string value = s.Substring(s.IndexOf("=")+1);
if (items.Keys.Contains(text))
items[text] = items[text] + "," + value;
else
items.Add(text, value);
}
foreach (var i in items)
{
collection.Add(i.Key, i.Value);
}
return collection;
}
you need to Deserialize using your model
try this
var response = JsonConvert.DeserializeObject<YourModel>(collection);
var name = response.name ;
var id = response.id;
use foreach loop , to get more records from list

Binding MVC model in controller which has a complex array

Most of my model is populated using $('form').serializeArray(), however an array of objects that form a paged grid need to be populated from its manager.
For example:
public JsonResult SubmitForm(MyViewModel input)
{
...
public class MyViewModel
{
[Display(Name = "Name")]
public string GridName { get; set; }
[Display(Name = "Description")]
public string GridDescription { get; set; }
public GridRow[] GridRows { get; set; }
The name and description would be picked up by serializeArray(), no issues there. If the GridRow is a string[], then it accepts me simply pushing multiple instances to it into the serialized array that jquery made:
var data = $('form').serializeArray();
for (var i in gridData) {
data.push({ name: 'GridRows', value: gridData[i].id });
}
$.ajax({
type: "POST",
url: '/Central/Results/SubmitForm',
dataType: "json",
data: data,
This way I can at least get an array of the IDs. However, it does not allow me to push the entire object into it (gridData[i]) when I want to populate the proper data type. I always get a null value when it reaches the controller.
Any idea how I need to handle the data in order for MVC to populate the model correctly? Thanks.
I'm pretty sure this is related to having to set the traditional option to true in your Ajax post. jQuery handles arrays a little differently than you'd expect, in terms of when they are posted to MVC controller actions.
So do this:
$.ajax({
type: "POST",
url: '/Central/Results/SubmitForm',
dataType: "json",
traditional: true,
data: data,
...
See this answer for more details.
Turns out just need to add a line and property reference, and add each variable separately.
for (var i in gridData) {
for (var j in gridData[i]) {
data.push({ name: 'GridRows[' + i + '].' + j, value: gridData[i][j] });
}
}
Edit: Just thought I'd post my updated helper method I wrote a while ago for this.
function serializeArray(obj, data, name) {
/// <summary>Turns an object into an MVC standard array of values </summary>
/// <param name="obj" type="Object">Object to serialise (required)</param>
/// <param name="data" type="Array">Array to append data to end of (optional)</param>
/// <param name="name" type="String">Name prefix for all entries (optional/ignore)</param>
if (!data || !(data instanceof Array)) {
data = [];
}
if (obj instanceof Array) {
if (!name) {
throw "Need an object name when converting an array";
}
for (var index = 0; index < obj.length; index++) {
data = serializeArray(obj[index], data, name + '[' + index + ']');
}
} else if (obj instanceof Object) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
data = serializeArray(obj[property], data, name ? (name + '.' + property) : property);
}
}
} else {
data.push({ name: name, value: obj });
}
return data;
}

using the result from jQuery into C#

I have this function in jquery which has the result array and how can I get this result array to C# code. Can anyone help me regarding this.
function generateData() {
var result = $('#accordion').sortable('toArray');
}
You could do this asynchronously through a web method call from script, such that you define a web method appropriately, then call and handle the data and potential return value, as desired. For example:
Defining a web method:
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static string HandleData(object[] data)
{
//handle data
return string.Empty;
}
Defining a reusable jQuery script method to handle web method calls:
function ExecutePageMethod(page, fn, paramArray, successFn, errorFn) {
var paramList = '';
if (paramArray.length > 0) {
for (var i = 0; i < paramArray.length; i += 2) {
if (paramList.length > 0) paramList += ',';
paramList += '"' + paramArray[i] + '":"' + paramArray[i + 1] + '"';
}
}
paramList = '{' + paramList + '}';
$.ajax({
type: "POST",
url: page + "/" + fn,
contentType: "application/json; charset=utf-8",
data: paramList,
dataType: "json",
success: successFn,
error: errorFn
});
}
And, of course, the call itself:
ExecutePageMethod("Default.aspx", "HandleData",
["data", result], successCallback, failureCallback);
Naturally we now need to make sure our callback methods exist:
function successCallback(result) {
var parsedResult = jQuery.parseJSON(result.d);
}
function failureCallback(result) {
}
Use a hiddenfield to store the result..
<asp:HiddenField id="hfResult" runat="server" />
JQuery
$('hfResult').val(result);
C#
String result = hfResult.Value;
Note that a hiddenField only holds a string, so you might need to use some kind of seperator to seperate your array objects..

Javascript Deserialize is returning the class name instead of actual object

So I'm running GetServerUpdateProgress() in the controller from a $.ajax call on my page. While debugging I can confirm that the variable: myobj is being properly created and filled with the correct data.
But when on the $.ajax success, I'm not getting the data in json format, instead I'm getting
a string of "TrackerMVC.ClassLib.UpdateAJAXProgress" - the objects type.
I've done this in the past with a .svc webservice and didn't have any problems getting the object values using this exact same method.
Any ideas? Thanks!
method:
public UpdateAJAXProgress GetServerUpdateProgress()
{
string BASE_URL = "http://localhost:55094";
string url = BASE_URL + "/Home/UpdateProgress";
WebRequest wr = WebRequest.Create(url);
wr.Credentials = CredentialCache.DefaultNetworkCredentials; // uses current windows user
var myojb = new UpdateAJAXProgress();
var response = (HttpWebResponse)wr.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
JavaScriptSerializer js = new JavaScriptSerializer();
var objText = reader.ReadToEnd();
myojb = (UpdateAJAXProgress)js.Deserialize(objText, typeof(UpdateAJAXProgress));
return myojb; // during debugging this object has the correct values in the correct format
}
class:
public class UpdateAJAXProgress
{
public int Completed { get; set; }
public int Total { get; set; }
}
javascript:
$.ajax({
type: "POST",
async: false,
url: '#(Url.Action("GetServerUpdateProgress","Charts"))',
contentType: "application/json; charset=utf-8",
success: function (data) {
console.log(data); // data being returned is: "TrackerMVC.ClassLib.UpdateAJAXProgress"
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.responseText);
}
});
You're misusing MVC.
You should declare your function as returning ActionResult, then return Json(myobj).
If you return a non-ActionResult from an MVC action, MVC will convert it to a string by calling ToString().

Categories

Resources