Sending an array of json objects to action with ajax in asp.net mvc 3

27,219

Solution 1

Instead of combining your arrays into another array, you're best of sending them as individual parameters to the action method, something like:

Assume we still have your two arrays:

var features = new Array();
var menuItems = new Array();
menuItems.push({ "Name": $(this).attr('name'), "isChecked": isChecked });
features.push({ "Name": $(this).attr('name'), "isChecked": isChecked });

Then in your JQuery ajax call do the following:

$.ajax({
        url: '@Url.Action("CheckPreferences")',
        type: 'POST',
        datatype: "json",
        traditional: true,
        data: { 
            menuItems: JSON.stringify(menuItems),
            features: JSON.stringify(features)
        },
        success: function () { window.alert('@Resource.AjaxSuccess'); },
        error: function (event, request, settings) {  
            window.alert('@Resource.AjaxError' + ' : ' + settings); },
        timeout: 20000
});

Then your controller method should be:

[HttpPost]
public ActionResult CheckPreferences(string menuItems, string features)
{
    var js = new JavaScriptSerializer();
    var deserializedMenuItems = (object[])js.DeserializeObject(menuItems);
    var deserializedFeatures = (object[])js.DeserializeObject(features);
    var myFeatures = new List<SJSonModel>();
    var myMenuItems = new List<SJSonModel>();

    if (deserializedFeatures != null)
    {
        foreach (Dictionary<string, object> newFeature in deserializedFeatures)
        {
            myFeatures.Add(new SJSonModel(newFeature));
        }
    }

    if (deserializedMenuItems != null)
    {
        foreach (Dictionary<string, object> newMenuItem in deserializedMenuItems)
        {
            myMenuItems.Add(new SJSonModel(newMenuItem));
        }
    }

    var myModelList = new SJSonModelList(myFeatures, myMenuItems);

    return Json("");

I also edited your classes by putting in a constructor to work with the above code, like so:

public class SJSonModel
{
    public SJSonModel(Dictionary<string, object> newFeature)
    {
        if (newFeature.ContainsKey("Name"))
        {
            Name = (string)newFeature["Name"];
        }
        if (newFeature.ContainsKey("isChecked"))
        {
            isChecked = bool.Parse((string)newFeature["isChecked"]);
        }
    }

    public string Name { get; set; }
    public bool isChecked { get; set; }
}

public class SJSonModelList
{
    public SJSonModelList(List<SJSonModel> features, List<SJSonModel> menuItems )
    {
        Features = features;
        MenuItems = menuItems;
    }

    public List<SJSonModel> Features { get; set; }
    public List<SJSonModel> MenuItems { get; set; }
}

Solution 2

Since you are passing serialized data from the client define postData as type string in your controller and then use JavascriptSerializer.Deserialize to deserialize the JSON into your object. This way you can also catch any errors that may occur during deserialization and debug the JSON that is sent over. One thing I am not sure if is if the Deserializer expects to match field names on case sensitivity. You define your arrays in the Model as "Features" and "MenuItems" whereas in the Javascript they are defined as "features" and "menuItems".

Share:
27,219
lilux_m
Author by

lilux_m

Updated on July 05, 2022

Comments

  • lilux_m
    lilux_m almost 2 years

    I hope anyone can help me (Sorry for my english). I have a problem when I want to send un array of arrays in ajax. My model is:

    public class SJSonModel
    {
        public string Name { get; set; }
        public bool isChecked { get; set; }     
    }
    
    public class SJSonModelList
    {
        public List<SJSonModel> Features { get; set; }
        public List<SJSonModel> MenuItems { get; set; }
    }
    

    The controller:

        [HttpPost]
        public ActionResult CheckPreferences(SJSonModelList postData)
        {
            BindUserFeatures(postData.Features);
    
            return Json(new { status = "Success", message = "Passed" });
        }
    

    The View simplified:

    <div class="Feature borderRadius Items">
        <h2>Title
            <input type="checkbox" class="Item" name="featureName"/>
        </h2> 
    
       <div class="FeatureDetails subItems">                 
            <a href="@Url…">featureName</a>
            <input type="checkbox" class="subItem" name="subItemName"/>
       </div> <!-- endOf FeatureDetails -->
    

    The JQuery code:

        var isChecked = false;
        var features = new Array();
        var menuItems = new Array();
        var postData = new Array();
    

    Here I fill the features, the menuItems with the featureName/menuItemName and isChecked boolean for each feature/menuItem

    menuItems.push({ "Name": $(this).attr('name'), "isChecked": isChecked });
    features.push({ "Name": $(this).attr('name'), "isChecked": isChecked });
    
    postData.push({ "features": features, "menuItems": menuItems });
    postData = JSON.stringify(postData);
    

    The ajax function:

        $(':submit').click(function () {
    
            postData.push({ "features": features, "menuItems": menuItems });
            postData = JSON.stringify(postData);
    
            $.ajax({
                     url: '@Url.Action("CheckPreferences")',
                     type: 'POST',
                     data: postData, 
                     contentType: "application/json; charset=utf-8",
                     dataType: "json",
                     traditional: true,
                     success: function () { window.alert('@Resource.AjaxSuccess'); },
                     error: function (event, request, settings) {  window.alert('@Resource.AjaxError' + ' : ' + settings); },
                     timeout: 20000
            }); //endOf $.ajax
        }); //endOf :submit.click function
    

    When I do alert(postData), in client side it contains the true values for each item but in the conroller the postData.Features and postData.MenuItems are null.

    I have tried to pass just one array to the controller too:

     features = JSON.stringify(features);
    

    in $.ajax:

    {… data: features,…}
    

    in controller:

     ActionResult CheckPreferences(IEnumerable<SJSonModel> features)
    

    and it works fine, but I don't know how to pass the array of json objects to my contoller. So I hope to retrieve the answer here :)

    Thank you very much.

  • lilux_m
    lilux_m about 12 years
    Hi, thank you for your message. I've done it yet it doesn't work, the values of menuItems and features are null
  • mattytommo
    mattytommo about 12 years
    Hi @LilitMR, check my new edit of my answer. I've tested that exact code and it works fine :)
  • Kevin Junghans
    Kevin Junghans about 12 years
    What exactly did not work? If you debug the application can you see JSON in the string that is returned to the controller? Or does it fail on deserialization?
  • lilux_m
    lilux_m about 12 years
    Hi , thank you so much for your message. I'll try it this monday at the office and I answer you quickly. Pass a fine WE :)
  • lilux_m
    lilux_m about 12 years
    Hi Kevin, thanks for your messages. I've just not used the serialization correctly, but it works fine now :)
  • lilux_m
    lilux_m about 12 years
    The problem was not the serialization but the postData: postData.push({ "features": features, "menuItems": menuItems }); postData = JSON.stringify(postData); ...$.ajax {...data: postData...}
  • lilux_m
    lilux_m about 12 years
    I shoud do data: { menuItems: JSON.stringify(menuItems), features: JSON.stringify(features) }
  • mattytommo
    mattytommo about 12 years
    Sweet :). Could you put the tick next to my answer and mark me as the answer? :)
  • mattytommo
    mattytommo about 12 years
    No problems :). Glad I could help.