AJAX не может передать массив контроллеру - PullRequest
1 голос
/ 05 августа 2020

Здравствуйте, у меня есть функция AJAX, которая делает это

     $("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()

            })

Журнал консоли дает мне эти данные

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

  
                             600601   S-16706, Uline  Поставка - Упаковочная коробка, 9 "x 8" x 8 ", MU / AX  1    1    202   0   76  126       700504   725M10, SuperBonder  Поставка - Клей-карандаш 0,28 "x 10"  0,125    0,125    265,5402   0   31,368  234,1722       

Может ли кто-нибудь помочь определить проблему, почему мой массив возвращает NULL?

Ответы [ 2 ]

0 голосов
/ 06 августа 2020

Проблема, по крайней мере частично, в том, что имена ваших свойств на клиенте не совпадают с именами ваших свойств на сервере. Например, на клиенте есть move_all, а на сервере - MoveAll. Чтобы привязка модели работала, они должны быть одинаковыми. Другая проблема в том, что типы данных также не совпадают. На клиенте move_all - это строка, тогда как на сервере MoveAll - это логическое значение. Не зная, как ваш клиентский код получает данные, трудно рекомендовать исправление для этого. Я думаю, что есть два подхода, которые вы могли бы использовать. Один из них - создать на сервере своего рода мостовую модель представления, которую вы используете для привязки данных. Затем вы должны скопировать данные из модели представления моста в ту, которая вам нужна, то есть в массив ItemPartViewModel. Другой подход, который вы могли бы использовать, - это сопоставить ваш массив на клиенте с другим массивом объектов, который соответствует вашему ItemPartViewModel.

Клиентский метод может быть реализован, например, путем изменения

item["p_id"] = p_id;

до

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

и для bools это будет работать

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

таким образом, теперь свойство и тип соответствуют c# viewModel. Вам нужно будет сделать то же самое для всех свойств, чтобы все они совпадали.

Вот демонстрация рабочего кода, который, надеюсь, поможет вам

Просмотреть модели и контроллер

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

Вид

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

Обратите внимание, как совпадают имена и типы моих свойств.

Вот скриншот того, что я вижу на вкладке сети инструментов разработчика, когда смотрю на пост.

запросить полезную нагрузку

Изменить: в вашем ItemPartViewModel измените

 public QtyActionTypeOriginal QtyActionTypeOriginal { get; set; }

на

  public QtyActionTypeOriginal[] QtyActionTypeOriginal { get; set; }

, потому что в клиенте это массив.

0 голосов
/ 06 августа 2020

Вы получаете null, потому что для одного из ваших атрибутов требуется [ValidateAntiForgeryToken]. Фактически он сработает 500 (Internal Server Error), так как он будет искать этот токен, прежде чем продолжить метод контроллера.

Одно из предложений - удалить ваш [ValidateAntiForgeryToken], и все должно работать нормально. Я попробовал ваш код, и он отлично работал без него.

Если вам нужен [ValidateAntiForgeryToken]. Я предлагаю вам изменить свой код следующим:

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

А затем десериализовать переданные вами данные на вашем контроллере:

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

Если вы передадите allParts в качестве параметра, вы все равно получите значение null, поэтому просто загрузите его в FormCollection и получите пару значений ключа, а затем десериализуйте его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...