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
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
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" x 8" x 8", MU/AX
<input id="Parts_0__PartName" name="Parts[0].PartName" type="hidden" value="Supply - Packing Carton, 9" x 8" x 8", 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" x 10"
<input id="Parts_1__PartName" name="Parts[1].PartName" type="hidden" value="Supply - Glue Stick 0.28" x 10"" />
</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
You are getting null because one of your Attribute requires
[ValidateAntiForgeryToken]
. It will in fact trigger500 (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:And then on your Controller, deserialize the data that you pass:
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.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 yourItemPartViewModel
.The client method can be achieved by for example changing
to
and for bools this will work
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
The view
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.
Edit: In your
ItemPartViewModel
changeto
because in the client it is an array.