skip to Main Content

Hello I have an AJAX function that does this

     $("button").click(function () {
                //var token = $("input[name='__RequestVerificationToken']", "#__AjaxAntiForgeryForm").val();
                var partArray = []; //for creating json array
                //looping through trs with class tr_clonePart
                $(".tr_clonePart").each(function () {
                    //for storing qtys and radios of cloned and original
                    var qty_actiontype_cloned = []
                    var datas_cloned = {};
                    var data_original = {}//fro original
                    var qty_actiontype_original = [];
                    //get infos for various fields
                    var p_id = $(this).find("td > a").attr('p-id');
                    var mfg = $(this).find("input.part_mfg").val();
                    var part_name = $(this).find("input.part_name").val();
                    var qty_in_item = $(this).find("input.qty_in_item").val();
                    var item = {};
                    //add values in json objects
                    item["PartID"] = p_id
                    item["MFGNumber"] = mfg
                    item["PartName"] = part_name
                    item["QtyInItem"] = qty_in_item
                    //chcking if part-class is checked or not
                    if ($(this).find("input[type='checkbox'].part-class").is(':checked')) {

                        var move_all = $(this).find("input[type='checkbox'].part-class").val();
                       // item["MoveAll"] = move_all
                        item["MoveAll"] = (move_all == "true");
                        var radios = $(this).find("input[type='radio'].radios:checked").val();
                        data_original["action_type"] = radios //adding value of radios in array
                        //item['radios_c'] = radios_c
                        var qty = $(this).find("input.qty").val();
                        data_original["qty"] = qty //adding value of qty in array
                        qty_actiontype_original.push(data_original)
                        item["QtyActionTypeOriginal"] = qty_actiontype_original
                        //item["qty"] = qtys
                    } else {
                        var qty = $(this).find("input.qty").val();
                        //for original data
                        data_original["qty"] = qty
                        var radios = $(this).find("input[type='radio'].radios:checked").val();
                        //for original data
                        data_original["action_type"] = radios
                        qty_actiontype_original.push(data_original)
                        item["QtyActionTypeOriginal"] = qty_actiontype_original
                        //item["MoveAll"] = "false"
                        item["MoveAll"] = (move_all == "false");
                        //looping through cloned trs
                        $(".tr_clonePart_" + p_id).each(function () {

                            var radios_clones = $(this).find("input[type='radio'].radios:checked").val();
                            //puuting value in cloned array
                            datas_cloned["action_type"] = radios_clones

                            console.log(radios_clones)
                            var qty_clones = $(this).find("input.qty").val();

                            datas_cloned["qty"] = qty_clones
                            //push data in cloned array
                            qty_actiontype_cloned.push(datas_cloned)

                        });
                        //push array in cloned json object
                        item["QtyActionTypeCloned"] = qty_actiontype_cloned


                    }
                    //getting other values
                    var OnHand = $(this).find("input.OnHand").val();
                    var onWorkOrder = $(this).find("input.onWorkOrder").val();
                    var committed = $(this).find("input.committed").val();
                    var fstk = $(this).find("input.fstk").val();
                    item["OnHand"] = OnHand
                    item["OnWorkOrder"] = onWorkOrder
                    item["Committed"] = committed
                    item["FSTK"] = fstk
                    //push json object in array
                    partArray.push(item)

                })
                console.log(partArray)

                //allParts = JSON.stringify(partArray);
                @*model = JSON.stringify(@Model);*@
                $.ajax({
                    type: "POST",
                    url: "@IGT.baseUrl/JODetails/SpecialOrderSelection",
                     contentType: "application/json; charset=utf-8",
                    data:
                        JSON.stringify({ allParts: partArray }),
                        @*JSON.stringify(@Model),*@


                    dataType: "json",
                    traditional: true,
                    success: function () {
                        alert('Success!');
                    },
                    error: function () {
                        alert('Error! ');
                    }
                });
                event.preventDefault()

            })

The console log gives me this data

ConsoleLog

So I want the array to be passed to my controller,

This is how my Controller method is setup

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult SpecialOrderSelection(ItemViewModel model, ItemPartViewModel[] allParts)
        {
       
            if (ModelState.IsValid)
            {
                JobOrder jobOrder = db.JobOrders.Find(model.Id);
                if (jobOrder == null)
                {
                    return HttpNotFound();
                }
                ViewBag.JobOrderID = jobOrder.ID;
                TempData["model"] = model;
                return RedirectToAction("SpecialOrderSummary", new { id = model.Id });
            }
            
            return View(model);
            
        }

But allParts always returns NULL.

Here is how the itemPartViewModel class is setup


public class QtyActionTypeCloned
    {
        public string action_type { get; set; }
        public string qty { get; set; }
    }

    public class QtyActionTypeOriginal
    {
        public string action_type { get; set; }
        public string qty { get; set; }
    }


public class ItemPartViewModel
    {
        [Required]
        public int ID { get; set; }
        public int ItemID { get; set; }
        public string PartID { get; set; }
        public string MFGNumber { get; set; }
        public string PartName { get; set; }
        public float QtyInItem { get; set; }
        public float Qty { get; set; }
        public bool MoveAll { get; set; }
        public float OnHand { get; set; }
        public float OnWorkOrder { get; set; }
        public float Committed { get; set; }
        public float FSTK { get; set; }

        public QtyActionTypeCloned qty_actiontype_cloned { get; set; }
        public QtyActionTypeOriginal qty_actiontype_original { get; set; }

        // This is the additional property to contain what user picks
        public PartActionType SelectedActionType { get; set; }
    }

Here is my payload for the array

payload

And here is my rendered html

  <tbody>
<input data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="Parts_0__ID" name="Parts[0].ID" type="hidden" value="346" /><input id="Parts_0__PartID" name="Parts[0].PartID" type="hidden" value="600601" /><input data-val="true" data-val-number="The field ItemID must be a number." data-val-required="The ItemID field is required." id="Parts_0__ItemID" name="Parts[0].ItemID" type="hidden" value="117" />                            <tr class="tr_clonePart">

                                <td>
                                    <a p-id=346 style='color:#FF00FF;' href='#'>600601</a>
                                </td>
                                <td>
                                    S-16706, Uline
                                    <input id="Parts_0__MFGNumber" name="Parts[0].MFGNumber" type="hidden" value="S-16706, Uline" />
                                </td>
                                <td>
                                    Supply - Packing Carton, 9&quot; x 8&quot; x 8&quot;, MU/AX
                                    <input id="Parts_0__PartName" name="Parts[0].PartName" type="hidden" value="Supply - Packing Carton, 9&quot; x 8&quot; x 8&quot;, MU/AX" />
                                </td>
                                <td style="font-weight:bold">
                                    <span class="qtyInItem">
                                        1
                                        <input data-val="true" data-val-number="The field QtyInItem must be a number." data-val-required="The QtyInItem field is required." id="Parts_0__QtyInItem" name="Parts[0].QtyInItem" type="hidden" value="1" />
                                    </span>

                                </td>
                                <td>
                                    <input checked="checked" class="part-class" data-partId="346" data-val="true" data-val-required="The MoveAll field is required." id="Parts_0__MoveAll" name="Parts[0].MoveAll" type="checkbox" value="true" /><input name="Parts[0].MoveAll" type="hidden" value="false" />
                                </td>

                                <td>
                                    <div class="AllTxt">
                                        1
                                    </div>
                                    <div class="editQty">
                                        <input class="qty text-box single-line" data-val="true" data-val-number="The field Qty must be a number." data-val-required="The Qty field is required." id="Parts_0__Qty" name="Parts[0].Qty" type="text" value="0" />
                                    </div>
                                </td>
                                <td>
                                    <span class="onHand">
                                        202
                                        <input data-val="true" data-val-number="The field OnHand must be a number." data-val-required="The OnHand field is required." id="Parts_0__OnHand" name="Parts[0].OnHand" type="hidden" value="202" />
                                    </span>
                                </td>
                                <td>
                                    <span class="onWorkOrder">
                                        0
                                        <input data-val="true" data-val-number="The field OnWorkOrder must be a number." data-val-required="The OnWorkOrder field is required." id="Parts_0__OnWorkOrder" name="Parts[0].OnWorkOrder" type="hidden" value="0" />
                                    </span>
                                </td>
                                <td>
                                    <span class="committed">
                                        76
                                        <input data-val="true" data-val-number="The field Committed must be a number." data-val-required="The Committed field is required." id="Parts_0__Committed" name="Parts[0].Committed" type="hidden" value="76" />
                                    </span>

                                <td>
                                    <span class="fstk">
                                        126
                                        <input data-val="true" data-val-number="The field FSTK must be a number." data-val-required="The FSTK field is required." id="Parts_0__FSTK" name="Parts[0].FSTK" type="hidden" value="126" />
                                    </span>
                                </td>


                                    <td>
                                        <input checked="checked" class="radios" data-val="true" data-val-required="The SelectedActionType field is required." id="Parts_0__SelectedActionType" name="Parts[0].SelectedActionType" type="radio" value="Transfer" />
                                    </td>
                                    <td>
                                        <input class="radios" id="Parts_0__SelectedActionType" name="Parts[0].SelectedActionType" type="radio" value="Harvest" />
                                    </td>
                                    <td>
                                        <input class="radios" id="Parts_0__SelectedActionType" name="Parts[0].SelectedActionType" type="radio" value="Dispose" />
                                    </td>
                            </tr>
<input data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="Parts_1__ID" name="Parts[1].ID" type="hidden" value="106" /><input id="Parts_1__PartID" name="Parts[1].PartID" type="hidden" value="700504" /><input data-val="true" data-val-number="The field ItemID must be a number." data-val-required="The ItemID field is required." id="Parts_1__ItemID" name="Parts[1].ItemID" type="hidden" value="117" />                            <tr class="tr_clonePart">

                                <td>
                                    <a p-id=106 style='color:#FF00FF;' href='#'>700504</a>
                                </td>
                                <td>
                                    725M10, SuperBonder
                                    <input id="Parts_1__MFGNumber" name="Parts[1].MFGNumber" type="hidden" value="725M10, SuperBonder" />
                                </td>
                                <td>
                                    Supply - Glue Stick 0.28&quot; x 10&quot;
                                    <input id="Parts_1__PartName" name="Parts[1].PartName" type="hidden" value="Supply - Glue Stick 0.28&quot; x 10&quot;" />
                                </td>
                                <td style="font-weight:bold">
                                    <span class="qtyInItem">
                                        0.125
                                        <input data-val="true" data-val-number="The field QtyInItem must be a number." data-val-required="The QtyInItem field is required." id="Parts_1__QtyInItem" name="Parts[1].QtyInItem" type="hidden" value="0.125" />
                                    </span>

                                </td>
                                <td>
                                    <input checked="checked" class="part-class" data-partId="106" data-val="true" data-val-required="The MoveAll field is required." id="Parts_1__MoveAll" name="Parts[1].MoveAll" type="checkbox" value="true" /><input name="Parts[1].MoveAll" type="hidden" value="false" />
                                </td>

                                <td>
                                    <div class="AllTxt">
                                        0.125
                                    </div>
                                    <div class="editQty">
                                        <input class="qty text-box single-line" data-val="true" data-val-number="The field Qty must be a number." data-val-required="The Qty field is required." id="Parts_1__Qty" name="Parts[1].Qty" type="text" value="0" />
                                    </div>
                                </td>
                                <td>
                                    <span class="onHand">
                                        265.5402
                                        <input data-val="true" data-val-number="The field OnHand must be a number." data-val-required="The OnHand field is required." id="Parts_1__OnHand" name="Parts[1].OnHand" type="hidden" value="265.5402" />
                                    </span>
                                </td>
                                <td>
                                    <span class="onWorkOrder">
                                        0
                                        <input data-val="true" data-val-number="The field OnWorkOrder must be a number." data-val-required="The OnWorkOrder field is required." id="Parts_1__OnWorkOrder" name="Parts[1].OnWorkOrder" type="hidden" value="0" />
                                    </span>
                                </td>
                                <td>
                                    <span class="committed">
                                        31.368
                                        <input data-val="true" data-val-number="The field Committed must be a number." data-val-required="The Committed field is required." id="Parts_1__Committed" name="Parts[1].Committed" type="hidden" value="31.368" />
                                    </span>

                                <td>
                                    <span class="fstk">
                                        234.1722
                                        <input data-val="true" data-val-number="The field FSTK must be a number." data-val-required="The FSTK field is required." id="Parts_1__FSTK" name="Parts[1].FSTK" type="hidden" value="234.1722" />
                                    </span>
                                </td>


                                    <td>
                                        <input checked="checked" class="radios" data-val="true" data-val-required="The SelectedActionType field is required." id="Parts_1__SelectedActionType" name="Parts[1].SelectedActionType" type="radio" value="Transfer" />
                                    </td>
                                    <td>
                                        <input class="radios" id="Parts_1__SelectedActionType" name="Parts[1].SelectedActionType" type="radio" value="Harvest" />
                                    </td>
                                    <td>
                                        <input class="radios" id="Parts_1__SelectedActionType" name="Parts[1].SelectedActionType" type="radio" value="Dispose" />
                                    </td>
                            </tr>

Can anybody help identify the problem as to why my array is returning back NULL?

2

Answers


  1. You are getting null because one of your Attribute requires [ValidateAntiForgeryToken]. It will in fact trigger 500 (Internal Server Error) since it will be looking for that token before proceeding on the Controller method.

    One suggestion is to remove your [ValidateAntiForgeryToken] and everything should work fine. I tried your code and it did work fine without it.

    If you want the [ValidateAntiForgeryToken]. I suggest your modify your code with this one:

       //Add the AntiForgeryToken on the your Post data:
       var token = $(':input[name="__RequestVerificationToken"]').val();
       $.ajax({
           type: "POST",
           url: "@IGT.baseUrl/JODetails/SpecialOrderSelection",
           //contentType: "application/json; charset=utf-8", --Remove this one
           //data: JSON.stringify({ allParts: array }), --Change this to new object below
           data: {
               '__RequestVerificationToken': token,
               'allParts': JSON.stringify(array)
           },
           dataType: "json",
           traditional: true                 
        });
    

    And then on your Controller, deserialize the data that you pass:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult SpecialOrderSelection(FormCollection data)
        {
          var results = JsonConvert.DeserializeObject<List<ItemPartViewModel>>(data["allParts"]);
        }
    

    If you pass allParts as parameter, you will still get null, so just get it on FormCollection and get the key value pair, then deserialize it.

    Login or Signup to reply.
  2. The problem, at least in part, is that your property names on the client do not match your property names on the server. For example on the client you have move_all and on the server you have MoveAll. For the model binding to work these need to be the same. The other problem is that the datatypes also don’t match. On the client move_all is a string whereas on the server MoveAll is a bool. Without knowing how your client side code is getting the data it is hard to recommend the fix for this. I think there are 2 approaches you could take. One is to create a kind of bridging viewmodel on the server which you use to bind the data. You then would copy the data from the bridging viewModel to the one you want it in i.e. an array of ItemPartViewModel. The other approach you could take is to map your array on the client to another array of objects that match your ItemPartViewModel.

    The client method can be achieved by for example changing

    item["p_id"] = p_id;
    

    to

    item["PartId"] = parseInt(p_id);
    

    and for bools this will work

    item["MoveAll"] = (move_all == "true");
    

    that way now the property and type match the c# viewModel. You will need to do similar for all the properties so they all match.

    Here is a demo of some working code which will hopefully help you

    View models and controller

    public class RawQtyActionTypeCloned
    {
        public string action_type { get; set; }
        public string qty { get; set; }
    }
    
    
    public class RawItemPartViewModel
    {
        public string move_all { get; set; }
        public string p_id { get; set; }
    
        public RawQtyActionTypeCloned qty_actiontype_cloned { get; set; }
    
    }
    
    public class JODetailsController : Controller
    {
        public ActionResult SpecialOrderSelection()
        {
            return View();
        }
    
        [HttpPost]
        public ActionResult SpecialOrderSelection(RawItemPartViewModel[] allParts)
        {
            return Content(allParts.Length.ToString());
        }
    }
    

    The view

    <button id="myButton">
        Click me
    </button>
    
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    
    <script>
    
        var array = [{
            move_all: "false",
            p_id: "346",
            qty_actiontype_cloned: [{
                action_type: "Dispose",
                qty: "1"
            }]
        }, {
            move_all: "true",
            p_id: "106",
            qty_actiontype_cloned: [{
                action_type: "Dispose",
                qty: "2"
            }]
        },
        {
            move_all: "true",
            p_id: "341",
            qty_actiontype_cloned: [{
                action_type: "Dispose",
                qty: "3"
            }]
        }
        ];
    
        $(document).ready(function () {
            var myButton = document.getElementById("myButton");
            myButton.addEventListener('click', onMyButtonClicked);
    
    
    
            function onMyButtonClicked(e) {
                e.preventDefault();
    
                     $.ajax({
                        type: "POST",
                         url: "/JODetails/SpecialOrderSelection",
                        contentType: "application/json; charset=utf-8",
                        data: JSON.stringify({ allParts: array }),
                        dataType: "json",
                        traditional: true
                    });
            }
    
        });
    </script>
    

    Notice how my property names and types are matching.

    Here is a screenshot of what I see in the network tab of the developer tools when I look at the post.

    request payload

    Edit: In your ItemPartViewModel change

     public QtyActionTypeOriginal QtyActionTypeOriginal { get; set; }
    

    to

      public QtyActionTypeOriginal[] QtyActionTypeOriginal { get; set; }
    

    because in the client it is an array.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search