I am working to create a page where in user will enter Customer related details (like Name, reference number,date) and below that fill in table (row count is dynamic, not sure how many rows user will have) with items received from Customer. Each table row has information related to item like Part-name, part-number,Quantity etc.. Along with this information we need to upload image (single image) of the physical copy of paper received. We have to send all this data to controller. Tried using FormData in javascript and ajax as below:
function Submitbtn() {
var shownVal = document.getElementById("CustomerId").value;
var CustomerId = document.querySelector("#CNList option[value='" + shownVal + "']").dataset.value;
var formData = new FormData();
var totalFiles = document.getElementById("imageUploadForm").files.length;
for (var i = 0; i < totalFiles; i++) {
var file = document.getElementById("imageUploadForm").files[i];
formData.append("imageUploadForm", file);
}
formData.append("CustomerRef", document.getElementById("CustomerRef").value);
formData.append("DateCreated",$("#DateCreated").val());
formData.append("ChallanDate", $("#ChallanDate").val());
$('.signal').show()
$.ajax({
url: '@Url.Action("SubmitData", "Material")',
type: "POST",
processData: false,
contentType: false,
data: formData,
success: function (response) {
$('.signal').hide();
if (data.result == false) {
alert(data.msg);
}
else {
alert("Saved succesfully");
$('#updateData').html(data);
}
},
error: function (er) {
alert(er);
}
});
}
ControllerCode:
public ActionResult SubmitData()
{
var pic = System.Web.HttpContext.Current.Request.Files["imageUploadForm"];
var id = System.Web.HttpContext.Current.Request.Params["InvoiceViewModel"];
Code processing
InvoiceViewModel vm = new InvoiceViewModel();
return PartialView("_AddNewTable", vm);
}
The above works fine but I am unable to send related table data. I could send values for CustomerRef, ChallanDate etc..but unable to append arraylist in this. In my view, if I append an arraylist in formData, unable to retrieve that in controller as it expects string values only.
If we do not send image, then all data is sent successfully to controller through ajax as below:
var shownVal = document.getElementById("CustomerId").value;
var CustomerId = document.querySelector("#CNList option[value='" + shownVal + "']").dataset.value;
var CustomerRef = document.getElementById("CustomerRef").value;
var DateCreated = $("#DateCreated").val();
var ChallanDate = $("#ChallanDate").val();
var InwardMaterialViewModel = {
DateCreated: DateCreated,
ChallanDate: ChallanDate,
CustomerId: CustomerId,
CustomerRef: CustomerRef,
Orders: InwardMaterialArray,
};
$.ajax({
beforeSend: function () {
$('.signal').show()
},
type: 'POST',
url: '@Url.Action("SubmitData", "Material")',
datatype: "json",
contentType: false,
processData: false,
data: InwardMaterialViewModel,
success: function (data) {
$('.signal').hide();
if (data.result == false) {
alert(data.msg);
}
else {
alert("Saved succesfully");
$('#updateData').html(data);
}
},
error: function (response) {
}
});
Tried placing the image file in InwardMaterialViewModel
but that didn't work.
Researched and found that we can send the data and image using <form action="" method="post" enctype="multipart/form-data">
method as explained in this link : https://cpratt.co/file-uploads-in-asp-net-mvc-with-view-models/
But then issue is the table data is not sent in model as we do not know how many rows user will input. Please advise.
More information as asked:
Main View:
@model xxxx.ViewModels.InwardMaterialViewModel
@{
ViewBag.Title = "AddNew";
}
<h2>AddNew</h2>
<link href="~/Content/Loader.css" rel="stylesheet" type="text/css" />
<div class="container margin-top-lg">
<div class="row">
<div class="col-lg-12">
<div class="col-sm-6">
<div class="form-group">
<label for="DateCreated">Date :</label>
@Html.TextBoxFor(d => d.DateCreated, "{0:dd/MM/yyyy}", new { id = "DateCreated", @class = "form-control", maxlength = "500" })
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="CustomerName">Customer Name :</label>
@*@Html.EditorFor(model => model.CustomerRef, new { id = "CustomerName", htmlAttributes = new { @class = "form-control" } })*@
@*@Html.DropDownListFor(p => p.Customers, new SelectList(Model.Customers, "CustomerId", "CustomerName"), "Select Name", new { id = "CustomerId", @class = "form-control" })*@
<input name="id" class="form-control" type="search" list="CNList" autocomplete="on" id="CustomerId" />
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="CustomerRef">Customer Ref. :</label>
@Html.TextBoxFor(d => d.CustomerRef, new { id = "CustomerRef", @class = "form-control", maxlength = "2000" })
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="CustomerRef">Challan Date :</label>
@Html.TextBoxFor(d => d.ChallanDate, "{0:dd/MM/yyyy}", new { id = "ChallanDate", @class = "form-control", maxlength = "500" })
</div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<div class="field" align="left">
<label for="ChallanImage">Challan Image :</label>
<input type="file" id="imageUploadForm" name="images" multiple="multiple" />
</div>
</div>
</div>
<br />
<div class="col-md-12">
<div id="updateData" class="table-responsive">
@Html.Partial("_AddNewTable")
</div>
</div>
<br>
</div>
<br />
<a href="@Url.Action("Index", "Home")" class="btn btn-primary btn-large pull-left"> Back</a>
<button type="submit" id="id" onclick="Submitbtn()" class="btn btn-success pull-right"> Submit </button>
Partial View : With table Data
@model xxxx.ViewModels.InwardMaterialViewModel
<table id="data_table">
<tr>
<th>Part Name</th>
<th>Part No</th>
<th>Serial No</th>
<th>Quantity</th>
<th>Repair Type</th>
<th>User</th>
<th>Remarks</th>
<th>Add/Delete</th>
</tr>
@foreach (var item in Model.Orders)
{
<tr>
<td>@item.PartName</td>
<td>@item.PartNo</td>
<td>@item.SerialNo</td>
<td>1</td>
<td>@item.RepairType</td>
<td>@item.UserName</td>
<td>@item.Remarks</td>
<td>
<input type='button' value='Delete' class='delete' onclick='Delete(@item.OrderGUID)' />
</td>
</tr>
}
<tfoot>
<tr>
<td><input name="id" class="form-control" type="search" list="lan" autocomplete="on" id="Part_Name" onchange = "getPartNumber()" /></td>
@*<td>@Html.DropDownListFor(p => p.Parts, new SelectList(Model.Parts, "PartName", "PartName"), "Select Name", new { id = "Part_Name", @class = "form-control", @onchange = "getPartNumber()" })</td>*@
<td><input type="text" class="form-control" id="Part_No" readonly/></td>
<td><input type="text" class="form-control" id="Serial_No" /></td>
<td><input type="text" class="form-control" id="Quantity" value="1" readonly/></td>
<td>
@Html.DropDownListFor(p => p.RepairType, new SelectList(Model.RepairTypeList, "Text", "Value"), "Select Type", new { id = "Repair_Type", @class = "form-control" })
</td>
<td>
@Html.DropDownListFor(p => p.Users, new SelectList(Model.Users, "UserId", "UserName"), "Select Name", new { id = "User", @class = "form-control" })
</td>
<td><input type="text" class="form-control" id="Remarks" /></td>
<td>
<input type="button" class="add" onclick="add_row();" value="Add Row">
</td>
</tr>
</tfoot>
</table>
<datalist id="lan">
@foreach (var item in Model.Parts)
{
<option id="@item.PartId" data-value="@item.PartId" value="@item.PartName"></option>
}
</datalist>
on add_row : The row data is entered into an array
var InwardMaterialArray = [];
function add_row() {
var Part_Name = document.getElementById("Part_Name").value;
var Part_No = document.getElementById("Part_No").value;
var Serial_No = document.getElementById("Serial_No").value;
if (Serial_No == "") {
alert("Serial No. must be filled out");
return false;
}
var Quantity = document.getElementById("Quantity").value;
var Repair_Type = document.getElementById("Repair_Type").value;
var User = document.getElementById("User").value;
var Remarks = document.getElementById("Remarks").value;
var OrderDto = {
PartName: Part_Name,
PartNo: Part_No,
SerialNo: Serial_No,
Qty: Quantity,
RepairType: Repair_Type,
AssignedUserId: User,
Remarks: Remarks,
};
InwardMaterialArray.push(OrderDto);
var InwardMaterialViewModel = {
Orders : InwardMaterialArray
};
$.ajax({
beforeSend: function () {
$('.signal').show()
},
type: 'POST',
url: '@Url.Action("AddRow", "Material")',
data: InwardMaterialViewModel,
success: function (data) {
$('.signal').hide();
if (data.result == false) {
alert(data.msg);
}
else {
$('#updateData').html(data);
}
},
error: function (response) {
}
});
}
All the data entered in rows is in arraylist InwardMaterialArray
populated through InwardMaterialArray.push(OrderDto);
in add_row
method above.
So I need to send this Array InwardMaterialArray
along with data filled in for customer above & image to controller, all at once.