Automatically bind model in Asp.Net MVC 4 by utilizing an array of objects in form submission

I have created an array of objects in JavaScript and need to send them back to the server using Ajax (jQuery is being used)

This is how the object array looks like in JavaScript:

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

The data is being sent back this way:

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

When I receive it in the controller action, this is what I am currently getting:

I have a c# object named JqColumn where I want to bind the posted data into, it has the following structure:

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

I assumed that adding a parameter in the controller action of type JqGridColumn[] columns would automatically bind the posted data, but unfortunately it's not working as expected (it creates an array with the correct number of elements, but each item has empty values)

Could someone guide me on what step I might be missing? Thank you!

UPDATE

Currently, I am manually mapping the items in my controller action like this:

    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;
    }

...this approach works well, but I am interested in learning the correct .Net MVC way to achieve this!

Answer №1

If you haven't specified a ModelBinder for the JqGridColumn type, the system will default to using the DefaultModelBinder. However:

  • The DefaultModelBinder only binds to public Properties, not Fields.

  • When binding Arrays, the expected format is columns[0].name, but you may be posting as columns[0][name].

To easily resolve this issue, consider sending your columns in JSON format instead of Name-Value-Pairs:

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

If you prefer not to modify your class structure, you can create and register a specific ModelBinder for JqGridColumn that supports Fields and 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
        };
    }
}

Remember to register the custom ModelBinder in App_Start/ModelBindingConfig.cs:

binders.Add(typeof(JqGridColumn), new JqGridColumnBinder());

Answer №2

Your JqGridColumn object requires properties, not fields in order to function properly. Check out this helpful reference for more information:

ASP.net MVC - Model binding excludes class fields?

Answer №3

Make sure to include the following settings when posting back:

$.ajax({
    url: '/MyController/MyAction',
    method: 'POST',
    traditional: true,
    dataType: json
    data: columns ,            
    sucess: function () { alert('Success'); }
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using React and TypeScript to enable file uploads

Seeking assistance in creating a basic single select upload component. When I click a button that contains a hidden input field, the file dialog opens and allows me to choose a file. The placeholder then changes to display the selected file name along with ...

Retrieve the final element of an array that is not empty

Looking for a simple way to retrieve the last occurrence of a key in a multidimensional array where "time_reported" is not NULL. For example, in the array provided below, the desired output would be key number 2 since it is the last array with an assigned ...

Invoking middleware within another middleware

I was recently following along with a web development tutorial on YouTube where the instructor introduced two middlewares called verifyToken and verifyUser. `verifyToken` const verifyToken = (req, res, next) => { const token = req.cookies.access_token ...

Finding an element based on its styling attribute, such as its position on the left or right side

One particular block that caught my eye is the slider element: <div id="sliderDispo" class="slider slider-dispo" data-slider-init="" data-slider-color="#0077b5 #EC6E31 #E40B0B" data-slider-step="33" > <div class="slider__interval" ...

Tips for organizing array objects into groups

I have a code snippet that looks like this: I am trying to figure out the best approach for this. I have a group: data [ { "date": "16/04/2020", "count": 0, "name": "A" }, { "date": "16/04/2020", "count": 1, ...

How can I access the object in jQuery's getJSON response from an API?

I am attempting to retrieve JSON data from an API and then access the "main" property of the "weather" object within the JSON. Here is the code I am using: $.getJSON("https://fcc-weather-api.glitch.me/api/current?lat=35&lon=139", function(json) { v ...

Why is there nothing showing up on the screen?

Just diving into Three.js and might've messed up somewhere. I'm trying to generate a geometry by using coordinates and surface data from a .k file. I checked the geometry.vertices and geometry.faces, they seem fine. I even played around with the ...

The HTML returned by Ajax does not appear to be aware of the JavaScript functions that have been applied to it

Currently, I am working on making AJAX requests that return elements in a table. Everything seems to be functioning well and displaying properly. However, I have noticed that any elements appended to the table which contain HTML like this: <div id="myI ...

Load a webpage with two dropdown menus in JavaScript/jQuery that have the same selection option pre-selected

I am facing an issue with two dropdown menus that should display the same value when the page loads. These dropdowns are used for filtering products on a WooCommerce website based on the selected vehicle. Initially, the user selects the Make, Model, and Se ...

Dynamically injecting Ace editor into an Angular 2 application

My goal is to dynamically load the ace editor into my angular2 application when a button is clicked. However, I keep encountering an error in the console that says: Error: ace.edit can't find div #editor Here's a snippet of the code I'm ...

Getting the barycentric coordinates of a triangle within a mesh using Three.js: A detailed guide

Currently using r71, I am facing a challenge where I need to click to raycast and scale a THREE.Geometry plane based on a user uploaded image. Additionally, I am looking to retrieve the barycentric coordinates of a point inside the clicked triangle on the ...

Transitioning from AngularJS to Angular: Updating the factory prototype

I've been in the process of migrating from AngularJS to Angular and have made a lot of progress. However, I am currently facing challenges with factories and prototypes. In this context, the Card object represents a playing card. function Car ...

The Heading I am trying to navigate to is partially obscured by the fixed topbar

I admit my code is quite messy, but this is my first project and I'm still figuring out how to properly structure it. I attempted to use margin with h2::before in CSS, and it sort of worked, but it caused other issues with the text layout. I've h ...

Line breaks in Vue v-tooltip functionality

Currently, I am implementing v-tooltip to add tooltip text to a button. My aim is to include a line break within the tooltip text, but I have been unable to determine if this is feasible using this method. After reviewing the documentation, I did not find ...

JavaScript- Tabbed Navigation with Lists as the Content

Currently, I am facing a frustrating issue in finding a suitable solution. My website uses tabs that utilize the UL, LI system, similar to most tab systems found in tutorials. The problem arises because the javascript on my site interferes with using the ...

Display the number in a formatted manner without displaying any zeros in the decimal part

Can you help me with a decimal number display issue I am having? <nested:text property="product.price" maxlength="5" onclick="javascript:validatePriceValue(this);"/> number displayed as 44 44.00 I want to use J ...

Encountering a "Vue is not defined" error in Laravel 5.8 while constructing a comment system using Vue.js

I'm struggling to implement a comment system using Vue.js in my Laravel project. Despite my efforts, I keep encountering a "Vue not defined" error in the console. Can anyone shed some light on why this might be happening? Below is the code snippet I&a ...

Unraveling exceptions in Node.js akin to handling them in Java

I'm seeking to develop a node application and I need guidance on exception handling. In Java, we utilize the exception class for this purpose. How can I achieve something similar in node? Are there any libraries available specifically for handling exc ...

Concealing and Revealing a Div Element in HTML

Every time the page is refreshed, I am encountering a strange issue where I need to double click a button in order to hide a block. Below is the code snippet for reference: <!DOCTYPE html> <html> <head> <meta name="viewport&quo ...