2

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)
    {
  • Check the link below to see if it will solve your issue [Halycon Solution](https://stackoverflow.com/questions/13242414/passing-a-list-of-objects-into-an-mvc-controller-method-using-jquery-ajax) – Samuel Akosile May 17 '19 at 23:31
  • @SamuelAkosile thank you, I already pass json data to controller successfully, if the controller method argument is not of type viewmodel. my issue is, my viewmodel already has data from view, how to add a json object to it, and keep the old values? – Abayomi Nidal May 17 '19 at 23:39

1 Answers1

0

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);
    }        
});
Jasen
  • 14,030
  • 3
  • 51
  • 68
  • Thank you very much. I handled the issue by collecting table data as JS array of objects, then stringify it, set a hidden field to stringified json, binding hidden field to viewmodel, to send digitalMaps with viewmodel, and deserialize the string into List an controller post action and save it in db. – Abayomi Nidal May 19 '19 at 01:17
  • The form is very long, couldn't let go of viewmodel since it has a lot of data annotation attributes that i'm counting on for validation – Abayomi Nidal May 19 '19 at 01:19