0

I want to pass a list to PartialView that has BeginCollectionItem(). Here is the code,

InquiryOrderViewModel

public class InquiryOrderViewModel
{
    public InquiryOrder InquiryOrder { get; set; }
    public List<InquiryOrderDetail> InquiryOrderDetails { get; set; }
    public List<InquiryComponentDetail> InquiryComponentDetails { get; set; }        
}

InquiryComponentDetail model

public class InquiryComponentDetail
{
    [Key]
    public int InquiryComponentDetailId { get; set; }

    public int DesignCodeId { get; set; }

    public int QualityReferenceId { get; set; }

    public int Height { get; set; }

    public int Length { get; set; }

    public int GscmComp { get; set; }

    public int Wastage { get; set; }

    public int TotalYarn { get; set; }

    public virtual DesignCodeQltyRef DesignCodeQltyRef { get; set; }

}

InquiryOrderIndex View and the Script to render multiple items at once

@model eKnittingData.InquiryOrderViewModel 

@using (Html.BeginForm("Save", "InquiryOrder"))
{
..........
<div id="cmpDts">
  @foreach (var item in Model.InquiryComponentDetails)
    {

    }
</div>
..........
}

<script>
        var prev;
        $(document).on('focus', '.class03', function () {
            prev = $(this).val();
        }).on('change', '.class03', function () {
            if (prev != "") {
                $.ajax({
                    url: '@Url.Action("ComponentDts", "InquiryOrder")', // dont hard code your url's
                    type: "GET",
                    data: { DesignCdId: $(this).val() }, // pass the selected value
                    success: function (data) {
                        $('.cmpCls').last().replaceWith(data);
                    }
                }); 
            }
            else {
                $.ajax({
                    url: '@Url.Action("ComponentDts", "InquiryOrder")', // dont hard code your url's
                    type: "GET",
                    data: { DesignCdId: $(this).val() }, // pass the selected value
                    success: function (data) {
                            $(".class03 option[value='']").remove();
                            $('#cmpDts').append(data);
                    }
                });
            }
        });
        </script>

The _DetailEditorRow PartialView which gives ddls with class03 and in main view where it got appended.(This is just to show you what is class03)

@model eKnittingData.InquiryOrderDetail
@using eKnitting.Helpers

@using (Html.BeginCollectionItem("InquiryOrderDetails"))
{
<div class="editorRow">
    @Html.DropDownListFor(a => a.ComponentId, (SelectList)ViewBag.CompList, "Select", new { Class = "class02" })
    @Html.DropDownListFor(a => a.DesignCodeId, (SelectList)ViewBag.DCodeList, "Select", new { Class = "class03" })
    @Html.TextBoxFor(a => a.NoOfParts, new { Class = "class01" })
    <a href="#" class="deleteRow">delete</a>
</div>
}

and in main view it got appended to 

<div id="editorRows">         
            @foreach (var item in Model.InquiryOrderDetails)
            {
                Html.RenderPartial("_DetailEditorRow", item);
            }           
    </div>

_ComponentDetails PartialView to render items(a list has been passed at once)

@model List<eKnittingData.InquiryComponentDetail>
@using eKnitting.Helpers

<div class="cmpCls">
@foreach(var icd in Model)
{
    using (Html.BeginCollectionItem("InquiryComponentDetails"))
    {
    <div class="innerCmpCls">
        @Html.DisplayFor(a => icd.DesignCodeId)
        @Html.DisplayFor(a => icd.QualityReferenceId)            
        @Html.TextBoxFor(a => icd.Height, new { Class="clsHeight clsSameHL"})
        @Html.TextBoxFor(a => icd.Length, new { Class = "clsLength clsSameHL" }) 
        @Html.TextBoxFor(a => icd.GscmComp, new { Class = "clsGscmComp clsSameHL" })
        @Html.TextBoxFor(A => icd.Wastage, new { Class = "clsWastage" })
        @Html.ActionLink("Fds", "View", new { id = icd.QualityReferenceId }, new { @class = "myLink", data_id = icd.QualityReferenceId })
        @Html.TextBoxFor(a => icd.TotalYarn, new { Class = "clsTotalYarn" })
        <br>
        <div class="popFds"></div>
    </div>
    }
}
</div> 

ActionResult that Passes a list at once and returns the PartialView

    public ActionResult ComponentDts(int DesignCdId)
    {
        var objContext = new KnittingdbContext();
        var QltyRefList = objContext.DesignCodeQltyRefs.Where(a=>a.DesignCodeId==DesignCdId).ToList();

        var iocdList = new List<InquiryComponentDetail>();

        foreach(DesignCodeQltyRef dcqr in QltyRefList)
        {
            iocdList.Add(new InquiryComponentDetail { 
                DesignCodeId=dcqr.DesignCodeId,
                QualityReferenceId=dcqr.QltyRefId
            });
        }
        return PartialView("_ComponentDetails", iocdList);
    }

ActionResult for GET

        var objContext = new KnittingdbContext();

        var newIovm = new InquiryOrderViewModel();
        var newIo = new InquiryOrder();
        var iocdL = new List<InquiryComponentDetail>();

        newIovm.InquiryOrder = newIo;
        newIovm.InquiryComponentDetails = iocdL;

        return View(newIovm);

ActionResult for POST

public ActionResult Save(InquiryOrderViewModel inquiryOrderViewModel)
{
    .........
}

When user selects an item from a dropdownlist(class03), the items related to that item are rendered to the view using the PartialView(_ComponentDetails') and get appended. Then user selects another item from another ddl(class03), the related items are rendered and appended after earlier appended ones. User can go on like this.

Rendering and appending items works fine. But for the PostBack even though i get the number of items in the list correctly(I checked it by putting a break point on POST ActionResult ) all items content show null values. Pls guide me in the correct way for achieving this. All help appreciated. Thanks!

Isuru
  • 950
  • 1
  • 13
  • 34
  • 1
    A few things that don't make sense - `@foreach (var item in Model.InquiryComponentDetails) { Html.RenderPartial("_ComponentDetails",item); }` is passing an instance of `InquiryComponentDetail` to the `_ComponentDetails.cshtml` partial view, but that view expects `List` so that code would throw an exception. Your script is referencing elements with `class="class03"` but your code does not show any elements with that class name - i.e. you have not shown us the correct code. –  Nov 14 '15 at 23:52
  • @Stephen Muecke, Thanks for replying :) I updated the question and now you can see where does this `class03` come from. It is the `Class` of ddls.And also i removed `RenderPartial` inside `foreach` since im not rendering an initial item at the beginning. If there is any unclear thing pls let me know.. – Isuru Nov 15 '15 at 03:16
  • @Stephen Muecke, Hope i have provided information such that you can get a clear idea. But if it's still not clear pls tell me. Im still struggling with this question – Isuru Nov 15 '15 at 05:15
  • Still confused. `InquiryOrderViewModel` does not contain a collection property of type `InquiryOrderDetail` so its unclear what its for. But if your properties are not not binding, you need to show your model for `InquiryComponentDetail` (first thing to check is do you properties have getters and setters) –  Nov 15 '15 at 06:57
  • @Stephen Muecke, yes there is a list of `InquiryOrderDetail` in viewmodel. I removed it from the question as i thought it is not relevant to question. Now i added it again. In `InquiryComponentDetail` model every property has getters and setters. Shall i update the question to show `InquiryComponentDetail` model also? – Isuru Nov 15 '15 at 07:22
  • Yes, show the model. –  Nov 15 '15 at 07:25
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/95161/discussion-between-stephen-muecke-and-isuru). –  Nov 15 '15 at 07:31

1 Answers1

1

Your _ComponentDetails view is generating form controls that have name attributes that look like (where ### is a Guid)

name="InquiryComponentDetail[###].icd.Height"

which does not match your model because typeof InquiryComponentDetail does not contain a property named icd. In order to bind to your model, your name attribute would need

name="InquiryComponentDetail[###].Height"

To generate the correct html, you will need 2 partials

_ComponentDetailsList.cshtml (this will be called by the ComponentDts() method using return PartialView("_ComponentDetailsList", iocdList);)

@model List<eKnittingData.InquiryComponentDetail>
<div class="cmpCls">
  @foreach(var item in Model)
  {
    Html.RenderPartial("_ComponentDetails", item);
  }
</div>

_ComponentDetails.cshtml

@model eKnittingData.InquiryComponentDetail
using (Html.BeginCollectionItem("InquiryComponentDetails"))
{
  <div class="innerCmpCls">
    @Html.DisplayFor(a => a.DesignCodeId)
    @Html.DisplayFor(a => a.QualityReferenceId)            
    @Html.TextBoxFor(a => a.Height, new { @class="clsHeight clsSameHL"}) // use @class, not Class
    @Html.TextBoxFor(a => a.Length, new { Class = "clsLength clsSameHL" }) 
    ....
  </div>
}
  • Yes it worked! you spent lot of time for me. Thank you very much :) Lastly could you pls tell me how to set the `id` of this after the above amendments `@Html.ActionLink("Fds", "View", new { id = icd.QualityReferenceId }, new { @class = "myLink", data_id = icd.QualityReferenceId })` in `_ComponentDetails.cshtml` view? – Isuru Nov 15 '15 at 08:45
  • should be just `new { id = Model.QualityReferenceId }` and `data_id = Model.QualityReferenceId ` –  Nov 15 '15 at 08:47
  • Ok.. Thank you very much :) – Isuru Nov 15 '15 at 08:49