Asp.Net MVC 4 Automatically bind model from array of objects in form post
Asked Answered
L

3

7

I have built an array of objects in JavaScript and want to post them back to the server via Ajax (Im using jQuery)

The JavaScript object array looks like this:

var columns = [
    { name: 'col 1', source: 'whatever', hidden: false, width: 50 },
    ...
];

Im posting it back like this:

$.post('/MyController/MyAction', { 'columns': columns });

On the controller action Im currently getting this:

enter image description here

I have a c# object called JqColumn that I want to bind the post into, it looks like this:

public class JqGridColumn
{
    public string name;
    public string source;
    public int width;
    public bool hidden;
}

So I thought that adding a parameter in the controller action of type JqGridColumn[] columns would automatically bind the posted data, but it doesn't (it generates a array, with the correct number of elements, but each item in the array has blank values)

Can anyone tell me what Im doing wrong? Thanks!

UPDATE

At present, I am manually binding the items in my controller action as follows:

    public void ColumnChooser(JqGridColumn[] columns)
    {
        for (int i = 0; i < columns.Length; i++)
        {
            columns[i].hidden = bool.Parse(Request.Form["columns[" + i + "][hidden]"]);
            columns[i].width = int.Parse(Request.Form["columns[" + i + "][width]"]);
            columns[i].name = Request.Form["columns[" + i + "][name]"];
            columns[i].source = Request.Form["columns[" + i + "][source]"];
        }
        return;
    }

...which works fine, but I'd really like to know the .Net MVC (correct) way to do it!

Lujan answered 23/4, 2014 at 10:54 Comment(3)
Have you tried making the fields on your JqGridColumn object into properties (ie, add a get & set) as it sounds the the model binder can't find the fieldsBrent
Tried and still no joy I'm afraid... :(Lujan
Have you tried using a WebApi Controller, the model binding might be handled differently using the WebAPI Controller as the default MVC binding (i think) depends on HTML Elements being posted back in a FormCollection.Leslee
M
10

Since you didn't register a specific ModelBinder for the JqGridColumn type, the DefaultModelBinder will be used. But:

  • It won't bind Fields, only public Properties.

  • The expected format for Array binding is columns[0].name while you're actually posting columns[0][name].

The problem could be solved easily if you'll simply send your columns in JSON format instead of Name-Value-Pairs:

$.ajax({
    url: '/MyController/MyAction',
    method: 'POST',
    contentType: 'application/json',
    data: JSON.stringify({ columns: columns })
});

Yet, if you don't like to change your class, you could register a ModelBinder specific for JqGridColumn and have it working even with Fields and current jQuery serialization:

public class JqGridColumnBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        string name = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + "[name]").AttemptedValue;
        string source = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + "[source]").AttemptedValue;
        int width = (int)bindingContext.ValueProvider.GetValue(bindingContext.ModelName + "[width]").ConvertTo(typeof(int));
        bool hidden = (bool)bindingContext.ValueProvider.GetValue(bindingContext.ModelName + "[hidden]").ConvertTo(typeof(bool));

        return new JqGridColumn
        {
            name = name,
            source = source,
            width = width,
            hidden = hidden
        };
    }
}

Then register it in App_Start/ModelBindingConfig.cs:

binders.Add(typeof(JqGridColumn), new JqGridColumnBinder());
Mew answered 24/4, 2014 at 15:0 Comment(1)
Thanks :) Didn't want to use a custom model binder, so the JSON.stringify for the win!Lujan
B
0

It's because your JqGridColumn object needs properties, not fields. see this question for reference:

ASP.net MVC - Model binding excludes class fields?

Brent answered 23/4, 2014 at 11:24 Comment(3)
Thanks for the reference. Unfortunately, even when the JqGridColumn variables are changed to properties, they still don't get bound.Lujan
You could try changing it to a List<JqGridColumn> instead of an array. I don't think it'll help as your getting the right number of items.Brent
On the off chance that it might work, I tried changing to a List<JqGridColumn> but still no binding :(Lujan
P
0

try post back with the traditional : true setting and dataType: json

$.ajax({
    url: '/MyController/MyAction',
    method: 'POST',
    traditional: true,
    dataType: json
    data: columns ,            
    sucess: function () { alert('Success'); }
});
Pentavalent answered 23/4, 2014 at 12:20 Comment(1)
Even with this change, the form post is still seen the same by the controller.Lujan

© 2022 - 2024 — McMap. All rights reserved.