0

I have done a lot of research on this with only half success. My problem is this: I have a view in ASP.NET MVC with a View Model, the problem is that one of my ViewModel properties is a list of objects seen below:

    public string ApplicationNo { get; set; }

    public int HSCode { get; set; }

    public IEnumerable<HSCode> HSCodes { get; set; }

    public string ItemDescription { get; set; }

    public int Weight { get; set; }

    public QuantityUnit Quantity { get; set; }        

    public int Cost { get; set; }

    public List<Item> Items { get; set; }

public class Item
    {
        public int HSCode { get; set; }
        public string ItemDescription { get; set; }
        public int Quantity { get; set; }
        public int Weight { get; set; }
        public double Cost { get; set; }
    }

I am rendering new items to the user using a partial view and ajax. Partial View:

@model ecims.ViewModels.NewApplicationViewModel

<table id="myTableData" class="table" cellpadding="2">
    @using (Html.BeginCollectionItem("newRow"))
    {
        if (Model.Items.Count != 0)
        {
            <tr>
                <th>
                    @Html.DisplayNameFor(model => @Model.HSCode)
                </th>
                <td>
                    @Html.EditorFor(model => @Model.Items.FirstOrDefault().HSCode, new { htmlAttributes = new { @class = "form-control", @value = @Model.Items.FirstOrDefault().HSCode.ToString() } })
                </td>              
                <th>
                    @Html.DisplayNameFor(model => @Model.Quantity)
                </th>
                <td>
                    @Html.EditorFor(model => @Model.Items.FirstOrDefault().Quantity, new { htmlAttributes = new { @class = "form-control", @value = @Model.Items.FirstOrDefault().Quantity.ToString() } })
                </td>
                <th>
                    @Html.DisplayNameFor(model => @Model.ItemDescription)
                </th>
                <td>
                    @Html.EditorFor(model => @Model.Items.FirstOrDefault().ItemDescription, "Item Description", new { htmlAttributes = new { @class = "form-control", @value = @Model.Items.FirstOrDefault().ItemDescription.ToString() } })
                </td>
                <th>
                    @Html.DisplayNameFor(model => @Model.Cost)
                </th>
                <td>
                    @Html.EditorFor(model => @Model.Items.FirstOrDefault().Cost, new { htmlAttributes = new { @class = "form-control", @value = @Model.Items.FirstOrDefault().Cost.ToString() } })
                </td>
            </tr>
        }
        else
        {
            <tr>
                <th>
                    @Html.EditorFor(model => @Model.HSCode, new { htmlAttributes = new { @class = "form-control", @value = "" } })
                </th>
                <td>
                    @Html.EditorFor(model => @Model.HSCode, new { htmlAttributes = new { @class = "form-control", @value = "" } })
                </td>
            </tr>
        }
    }
</table>

My AJAX function is here:

<script type="text/javascript">


        $("#add").on('click', function () {

            var HSCode = $('#hsCode').val();
            var ItemDescription = $('#descrip').val();
            var Quantity = $('#qty').val();
            var QuantityUnit = $('#qtyUnit').val();
            var Cost = $('#cost').val();

            $.ajax({
                async: false,
                data: { 'HSCode': HSCode, 'Quantity': Quantity, 'ItemDescription': ItemDescription, 'QuantityUnit': QuantityUnit, 'Cost': Cost },
                url: '/CreateEUCApplication/CreateNewEUCItem',
                success: function (partialView) {
                    $('#newRow').append(partialView);
                }
            });
        });

</script>

I would like the 'Item' list in the ViewModel to be updated with new entries when the user clicks on the 'Add' button. Currently, my ajax method updates the view with new items successfully but when I post to the controller, the 'Model.Item' list is empty which throws up an exception.

How do I post a list in my ViewModel to my controller for processing? Thank you. PS: Any edits/suggestions to improve my code are more than welcome(I'm a novice trying to get better at this :-))

  • None of your code makes sense. Suggest you look at [this answer](http://stackoverflow.com/questions/40539321/partial-view-passing-a-collection-using-the-html-begincollectionitem-helper/40541892#40541892). (and unders no circumstances do you ever set the `value` attribute when using `HtmlHelper` methods to generate form controls) –  Nov 29 '17 at 21:30
  • Thanks for your suggestion, Steve. I am working through your solution on that answer now. Will post an update on how that goes. – Ozone Developer Nov 30 '17 at 08:26
  • Hi @StephenMuecke , I have gone through the post you suggested and edited my view model, view and controller to fit your posted solution on said post. The issue now is that when I click the add button, a new row is created as expected but all its values are set to 0, not the values on my form. The view has dropdown lists and textboxes for HSCode, Weight etc, I would like those values to be what is held by the partial view when the user clicks add. I noticed that my view model design is different from the one you posted, as I have a list of Item objects and yours holds a list of viewmodels. – Ozone Developer Nov 30 '17 at 10:27
  • How do I bind the values of the items on my view to the being rendered by my partial view? Thank you. – Ozone Developer Nov 30 '17 at 10:29
  • You can just completely change the question and invalidate comments and answers that have been already added, and the fact you say _the Model.Item list is empty_ when it will not be makes no sense. I will roll back your changes shortly. You need to ask a new question, but I do not understand what you mean by _but all its values are set to 0, not the values on my form_. For a start, your the model in your partial needs to be `@model yourAssembly.Item` since that is the object your adding, not `NewApplicationViewModel` (whatever that is) –  Nov 30 '17 at 10:43

1 Answers1

0

To start off, you don't need to use @ within the Html helper methods; change:

@Html.DisplayNameFor(model => @Model.HSCode)

to

@Html.DisplayNameFor(model => Model.HSCode)

There are some examples of using BeginCollectionItem online: MVC 5 Dynamic Rows with BeginCollectionItem

You don't need to use Html.BeginCollectionItem; on my blog there is another option, which is a little more of a complicated setup. My solution uses Kendo UI, but that is not a requirement.

Brian Mains
  • 50,520
  • 35
  • 148
  • 257