how to bind json data to existing viewmodel - mvc5

2019-07-22 20:38发布

问题:

I have a long strongly-typed form which its inputs are bound with viewmodel as html helpers, while i have a table that's not strongly-typed, it's generated when user clicks Add button, and i collect its data as json. how to map json data to viewmodel and send as one unit to post action in controller in ajax call?

view

@model SIServices.ViewModels.SODViewModel
@using (Html.BeginForm("Initiate", "SOD", FormMethod.Post, new { id = 
  "initiateSOD" })) // enctype = "multipart/form-data"
 {
      @Html.AntiForgeryToken()

      ...

      @* form inputs as html helpers *@
      @* html table data is collected as json *@

javasctipt

   var cols = [];
   cols.push("DIGITAL_FILE_TYPE_ID");
   cols.push("DOCUMENT_LAPI_ID");
   var DigitalMaps = [];
   $("table#digital-map-table tbody tr").each(function () {
   data = {};

   var selectedDigitalMapVal = $(this).data("selectedDigitalMapVal");
   data[cols[0]] = selectedDigitalMapVal;
   var documentId = $(this).data("documentID");
   data[cols[1]] = documentId.toString();                       
   DigitalMaps.push(data);
   data = {};

   });

    var headers = { __RequestVerificationToken: 
      $('input[name="__RequestVerificationToken"]').val() };

                if (DigitalMaps != null) {
                    $.ajax({
                        headers: headers,
                        url: "@Url.Action("Initiate")",
                        type: "POST",
                        cache: false,
                        contentType: "application/json; charset=utf-8",
                        data: DigitalMaps,
                        dataType: "json",
                        success: function (succ) {
                            console.log(succ);
                        },
                        error: function (err) {
                            console.log(err.statusText);
                        }
                    });
                }

viewmodel

   namespace SIServices.ViewModels
   {
       public class SODViewModel
       {
          // a lot of properties - around 50
          public int? DigitalMapId { get; set; }
          public List<DIGITAL_MAPS> DigitalMaps { get; set; }

controller

    [HttpPost]
    [ValidateHeaderAntiForgeryToken]
    public ActionResult Initiate(SODViewModel vm)
    {

回答1:

You've got a form, backed by the view model, which you need to convert to a JavaScript Object so you can attach the DigitalMaps array.

To tackle the first problem you can use one of the answers here Convert form data to JavaScript object with jQuery.

Below, I use the function from here https://stackoverflow.com/a/22420377/2030565. This worked on a simple form but I haven't tried to find edge cases.

$.fn.serializeObject = function() {
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name]) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

So we can capture the form and convert it to a JavaScript object:

var model = $("form").serializeObject();

Now we can attach the property for the collection:

var digitalMapRows = [];
model.DigitalMaps = digitalMapRows;

Then post with ajax

$.ajax({
    headers: headers,
    url: "@Url.Action("Initiate")",
    type: "POST",
    cache: false,
    contentType: "application/json; charset=utf-8",
    data: JSON.stringify(model),
    dataType: "json",
    success: function (succ) {
        console.log(succ);
    }        
});