I try to create a non-array collection in jQuery. Below is a simplified version of what I am trying to do:
var Categories = ["Softdrink", "Cheese", "Fruit" ];
var Cats = $();
var temp;
for (var i = 0; i < Categories .length; i++) {
temp = { Id: i, Category: Categories[i] };
Cats = Cats.add(temp);
}
In the above, it ends up creating an array called "Cats".
My question is, how to create a non-array collection, ie, when it gets sent from the client side thru Ajax to the server, the server will receive IEnumerable or ICollection, but not an array.
In JavaScript arrays are collections, and objects are dictionaries. As json is based on JavaScript syntax, any .net IEnumable or ICollection will be mapped to a json array.
in .net json deserialization ICollection and IEnumerable are interfaces, with no constructor. This mean if you are binding to one they must exist or you need to supply a custom serializer. In practice this means an action parameter can not be an interface.
If the model has Interface property, the model constructor must initialize it.
Note: jquery objects are arrays with extended methods via their prototype.
Actually my code will generate an array of JSON objects. If I modify the code to the one below, which is equivalent to the one from yesterday, it is clearer that "temp" is a JSON object:
var Categories = ["Softdrink", "Cheese", "Fruit"];
var Cats = $();
var temp;
for (var i = 0; i < Categories.length; i++) { temp = { Id: i }; temp["Category"] = Categories[i];
Cats = Cats.add(temp);
}
Here I am on the client side, in the jQuery, trying to send a collection of JSON objects thru AJAX, to the server, for a Web API Update operation. The server side will take care of the serialization/deserialization.
you really should not be using $() (empty jquery array object) as your base.
var Categories = ["Softdrink", "Cheese", "Fruit"];
var Cats = [];
var temp;
for (var i = 0; i < Categories.length; i++) {
temp = {
Id: i,
Category: Categories[i]
};
Cats = Cats.push(temp);
}
// or better yet:
var Categories = ["Softdrink", "Cheese", "Fruit"];
var Cats = Categories.map(function(c,i) {
return {
Id: i,
Category: c
}
);
public class Category
{
public int Id {get; set;}
public string Category {get; set;}
}
// pass as collection
public IHttpActionResult MyMethod (List<Category> cats)
{
}
// pass as array
public IHttpActionResult MyMethod2 (Category[] cats)
{
}
// will not work without writing custom model binder as binder can not create instance of interface
public IHttpActionResult MyMethod3 (IEnumerable<Category> cats)
{
}
in .net json deserialization ICollection and IEnumerable are interfaces, with no constructor.This mean if
you are binding to one they must exist or you need to supply a custom serializer. In practice this means
an action parameter can not be an interface. If the model has Interface property, the model constructor
must initialize it.
(1) When I am sending data from client side AJAX to the.net server, does it need to be serialized/deserialized?
(2) What is an action parameter in jQuery?
(3) I am confused by "in .net json deserialization ICollection and IEnumerable are interfaces, with no constructor.
This mean if you are binding to one they must exist or you need to supply a custom serializer".
Could you please elaborate and provide an example?
When I sent my previous response, I have not read this one from you.
You have partially answered my questions.Thanks.
I still have questions:
(1) Does your comment regarding IHttpActionResult equally applicable to HttpResponseMessage?
(2) About "will not work without writing custom model binder as binder can not create instance of interface", could you give a rough sketch of an example of a custom binder?
1) http request are a byte stream. to send data from the client to the server, it must be serialized (json, form posts, and xml are common formats).
2) by action parameter I meant, a parameter to a MVC action. the MVC binder deserializes the query string and post data t parameters
3) you can not create an instance of an interface
var list = new List<string>(); // valid
var list2 = new IEnumerable<string>(); // error
var list3 = (IEnumerable<string>) list; // extract interface from class instance
4) there is a difference in MVC action binding and webapi binding as webapi binding is stricter parsing (and faster) in deserialization, but neither will support an interface for binding. if the parameter has am interface property the contractor must initial
it.
for json:
{
list: {"one","two"}
}
public class MyModel
{
public IEnumable List<string> {get; set;}
}
public class MyModel2
{
public IEnumable List<string> {get; set;} = new List<string>();
}
// fails binding
public HttpResponseMessage Get(MyModel model)
{
}
// works
public HttpResponseMessage Get(MyModel2 model)
{
}
Thanks so much for your comprehensive explanation.
The IEnumerable<> (or ICollection<>) in my case is actually a property within a class, (it did not show because I tried to focus on handling that collection property) and I instantiate the property with HashSet(), which should be OK.
However, there is a problem with the code you provided:
var Cats = [];
var temp;
for (var i = 0; i < Categories.length; i++) {
//temp = { Id: i, Category: Categories[i] };
temp = { Id: i };
temp["Category"] = Categories[i];
Cats = Cats.push(temp);
}
In the above, "Cats = Cats.push(temp);" does not work. (the "push" does not even show up in intellesence).
In my code I include only jquery-3.3.1.js. Do I miss anything?
all arrays have a push method, it appends to the end. But it returns the new length, so the assign changed the variable. I would always use .map for this use case.
Member
19 Points
66 Posts
Fail to set up a jQuery collection
Jun 12, 2020 05:04 AM|GoldenMicrosoft|LINK
Hi,
I try to create a non-array collection in jQuery. Below is a simplified version of what I am trying to do:
var Categories = ["Softdrink", "Cheese", "Fruit" ];
var Cats = $();
var temp;
for (var i = 0; i < Categories .length; i++) {
temp = { Id: i, Category: Categories[i] };
Cats = Cats.add(temp);
}
In the above, it ends up creating an array called "Cats".
My question is, how to create a non-array collection, ie, when it gets sent from the client side thru Ajax to the server, the server will receive IEnumerable or ICollection, but not an array.
Appreciate your help,
Contributor
3140 Points
983 Posts
Re: Fail to set up a jQuery collection
Jun 12, 2020 10:23 AM|Yang Shen|LINK
Hi GoldenMicrosoft,
Is it ok for you to convert the Cats to json string and then pass to the server, serialize it and conver to other type, like a list?
Best Regard,
Yang Shen
All-Star
58174 Points
15647 Posts
Re: Fail to set up a jQuery collection
Jun 12, 2020 02:43 PM|bruce (sqlwork.com)|LINK
In JavaScript arrays are collections, and objects are dictionaries. As json is based on JavaScript syntax, any .net IEnumable or ICollection will be mapped to a json array.
in .net json deserialization ICollection and IEnumerable are interfaces, with no constructor. This mean if you are binding to one they must exist or you need to supply a custom serializer. In practice this means an action parameter can not be an interface. If the model has Interface property, the model constructor must initialize it.
Note: jquery objects are arrays with extended methods via their prototype.
Member
19 Points
66 Posts
Re: Fail to set up a jQuery collection
Jun 12, 2020 04:33 PM|GoldenMicrosoft|LINK
Hi Yang Shen,
Thanks for your response.
Actually my code will generate an array of JSON objects. If I modify the code to the one below, which is equivalent to the one from yesterday, it is clearer that "temp" is a JSON object:
var Categories = ["Softdrink", "Cheese", "Fruit"];
var Cats = $();
var temp;
for (var i = 0; i < Categories.length; i++) {
temp = { Id: i };
temp["Category"] = Categories[i];
Cats = Cats.add(temp);
}
Here I am on the client side, in the jQuery, trying to send a collection of JSON objects thru AJAX, to the server, for a Web API Update operation. The server side will take care of the serialization/deserialization.
Please correct me if my understanding is wrong.
All-Star
58174 Points
15647 Posts
Re: Fail to set up a jQuery collection
Jun 12, 2020 05:41 PM|bruce (sqlwork.com)|LINK
you really should not be using $() (empty jquery array object) as your base.
either of which produces the following JSON
which can be used in the following actions:
Member
19 Points
66 Posts
Re: Fail to set up a jQuery collection
Jun 12, 2020 05:53 PM|GoldenMicrosoft|LINK
Hi Bruce,
Thanks for your response.
in .net json deserialization ICollection and IEnumerable are interfaces, with no constructor.This mean if
you are binding to one they must exist or you need to supply a custom serializer. In practice this means
an action parameter can not be an interface. If the model has Interface property, the model constructor
must initialize it.
(1) When I am sending data from client side AJAX to the.net server, does it need to be serialized/deserialized?
(2) What is an action parameter in jQuery?
(3) I am confused by "in .net json deserialization ICollection and IEnumerable are interfaces, with no constructor.
This mean if you are binding to one they must exist or you need to supply a custom serializer".
Could you please elaborate and provide an example?
Member
19 Points
66 Posts
Re: Fail to set up a jQuery collection
Jun 12, 2020 06:28 PM|GoldenMicrosoft|LINK
Hi Bruce,
When I sent my previous response, I have not read this one from you.
You have partially answered my questions.Thanks.
I still have questions:
(1) Does your comment regarding IHttpActionResult equally applicable to HttpResponseMessage?
(2) About "will not work without writing custom model binder as binder can not create instance of interface", could you give a rough sketch of an example of a custom binder?
Thanks again,
Golden
All-Star
58174 Points
15647 Posts
Re: Fail to set up a jQuery collection
Jun 12, 2020 08:00 PM|bruce (sqlwork.com)|LINK
1) http request are a byte stream. to send data from the client to the server, it must be serialized (json, form posts, and xml are common formats).
2) by action parameter I meant, a parameter to a MVC action. the MVC binder deserializes the query string and post data t parameters
3) you can not create an instance of an interface
var list = new List<string>(); // valid
var list2 = new IEnumerable<string>(); // error
var list3 = (IEnumerable<string>) list; // extract interface from class instance
4) there is a difference in MVC action binding and webapi binding as webapi binding is stricter parsing (and faster) in deserialization, but neither will support an interface for binding. if the parameter has am interface property the contractor must initial it.
5) see custom model binder:
https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
Member
19 Points
66 Posts
Re: Fail to set up a jQuery collection
Jun 13, 2020 02:13 AM|GoldenMicrosoft|LINK
Hi Bruse,
Thanks so much for your comprehensive explanation.
The IEnumerable<> (or ICollection<>) in my case is actually a property within a class, (it did not show because I tried to focus on handling that collection property) and I instantiate the property with HashSet(), which should be OK.
However, there is a problem with the code you provided:
In the above, "Cats = Cats.push(temp);" does not work. (the "push" does not even show up in intellesence).
In my code I include only jquery-3.3.1.js. Do I miss anything?
Golden
All-Star
58174 Points
15647 Posts
Re: Fail to set up a jQuery collection
Jun 13, 2020 03:30 PM|bruce (sqlwork.com)|LINK
Sorry, was editing your code. Should be just;
Cats.push(temp);
all arrays have a push method, it appends to the end. But it returns the new length, so the assign changed the variable. I would always use .map for this use case.
Member
19 Points
66 Posts
Re: Fail to set up a jQuery collection
Jun 14, 2020 06:39 PM|GoldenMicrosoft|LINK
Hi Bruce,
Your solution absolutely works! Thanks a great deal!
Please also comment on the following:
Since an Array is built on top of a basic Colection, an array "Cats" should work for both:
and
Your solution works for both above.
Thanks again,
Golden,