Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Posting serialized form data AND additional data to MVC controller?

I'm trying to tack on some additional data a POST request sent to my server. Originally, I was sending just several forms worth of information:

$.ajax({
    url: 'SaveAllDetails',
    type: 'POST',
    data: $('form').serialize(),
    dataType: 'json'
});

and the MVC Controller method:

[HttpPost]
public ActionResult SaveAllDetails([Bind(Prefix = "order")]ExistingOrderDetailsModel existingOrderDetailsModel, 
    [Bind(Prefix = "task")]ExistingTaskDetailsModel existingTaskDetailsModel, [Bind(Prefix = "device")]DeviceDetailsModel deviceDetailsModel)
{
    ....
}

This works great. MVC's model binder is able to correctly de-serialize the URL-encoded string.

Now, requirements have changed. I need to send an additional array of data along with my three forms. This array of data is not held within a form and does not have a binding prefix. I need to do this all in the same Controller method because all validation needs to be performed inside of a single transaction.

So, I've now got:

var subcomponentsGridRows = JSON.stringify(subcomponentsDetailsView.getAllGridData());
var existingOrderDetailsFormData = $('form#existingOrderDetailsForm').serialize();
var existingTaskDetailsFormData = $('form#existingTaskDetailsForm').serialize();
var deviceDetailsFormData = $('form#existingDeviceDetailsForm').serialize()

$.ajax({
    url: 'SaveAllDetails',
    type: 'POST',
    data: {
        existingOrderDetailsModel: existingOrderDetailsFormData,
        existingTaskDetailsModel: existingTaskDetailsFormData,
        deviceDetailsModel: deviceDetailsFormData,
        subcomponentsGridRows: subcomponentsGridRows
    },
    dataType: 'json'
});

This doesn't work for at least one reason. Each form is represented as a URL-encoded string. subcomponentsGridRows is a JSON structure. The MVC model binder isn't capable of deciphering both types of information in one go as far as I can tell.

What's a good way to go about tackling this problem?

like image 810
Sean Anderson Avatar asked Feb 13 '14 21:02

Sean Anderson


1 Answers

You might find the following plugin useful.

Here's how it might be useful to you. Let's start by cleaning your controller action by defining a view model:

public class MyViewModel
{
    public ExistingOrderDetailsModel Order { get; set; }
    public ExistingTaskDetailsModel Task  { get; set; }
    public DeviceDetailsModel Device  { get; set; }

    public AdditionalRowsViewModel[] AdditionalRows { get; set; }
}

In this example the AdditionalRowsViewModel will obviously hold the additional information you are trying to pass to the controller action.

And then your controller action will become:

[HttpPost]
public ActionResult SaveAllDetails(MyViewModel model)
{
    ....
}

OK, this step was absolutely necessary, it's just that when I see a controller action taking more than 1 parameter I simply define a view model.

And finally let's adapt our AJAX call:

$.ajax({
    url: 'SaveAllDetails',
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify({
        order: $('form#existingOrderDetailsForm').serializeObject(),
        task: $('form#existingTaskDetailsForm').serializeObject(),
        device: $('form#existingDeviceDetailsForm').serializeObject(),
        additionalRows: subcomponentsDetailsView.getAllGridData()
    }),
    success: function(result) {
        // do something with the result of the AJAX call here
    }
});

Things to notice:

  1. Get rid of this dataType: 'json' parameter in your AJAX request. You are using ASP.NET MVC and hopefully you are returning a Jsonresult from your controller action which is successfully setting the Content-Type response header to the correct value. jQuery is intelligent enough to use the value of this response header and pre-process the result variable that will be passed to the success callback of your AJAX request. So in this case you will already get a javascript object
  2. Since you are sending JSON to the server in your AJAX request you need to properly specify the contentType: application/json parameter. Otherwise how do you expect that ASP.NET MVC will know that the client is sending JSON and apply the correct model binder? By the way the default Content-Type request header that jQuery will send is application/x-www-form-urlencoded, so if you are sending JSON payload in your POST request that would be a conflict and violation of the protocol.
like image 96
Darin Dimitrov Avatar answered Oct 23 '22 08:10

Darin Dimitrov