0

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.

Gaurav
  • 535
  • 1
  • 8
  • 28
  • What table data are you referring to? All your are posting is files plus some properties of an object. There is nothing relating to _Part-name, part-number,Quantity etc_. And are those a collection. You need to give us a lot mote information including your model and view. And you should be binding to your model in the POST method. –  Jun 28 '18 at 05:24
  • If you have generated your view correctly, then all you need is `var formdata = new FormData($('form').get(0));` to correctly serialize all your form controls (refer [this answer](https://stackoverflow.com/questions/29293637/how-to-append-whole-set-of-model-to-formdata-and-obtain-it-in-mvc/29293681#29293681). –  Jun 28 '18 at 05:26
  • @StephenMuecke Thanks for replying. The form data is correctly serialized in controller. Only thing missing is the array list with table data. I am unable to figure how to send an array through formdata. As asked, edited the code with views. Thanks. – Gaurav Jun 28 '18 at 06:25
  • Almost everything your doing here us wrong (and your writing a lot of unnecessary code. First if you are wanting to dynamically add collection items, then refer [here](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) and [here](http://stackoverflow.com/questions/40539321/partial-view-passing-a-collection-using-the-html-begincollectionitem-helper/40541892#40541892). –  Jun 28 '18 at 06:31
  • Its not clear why you want to stay in the same page after editing, but if you want to append collection items to `FormData`, then it needs to be in the format `formData.append('PropertyName[0].PropertyName', value)` - i.e. each property of each item needs to be appended as a name/value pair (but if you view is generated correctly as per the links in my previous comment, then its just as per the link in my 2nd comment –  Jun 28 '18 at 06:35

0 Answers0