0

enter image description here I am creating a DataEntry Screen which have a three dropdownlist at the top which is cascaded using ajax . And A partial view is also rendered using Ajax which will show all the items against that selection user made on the dropdowns. The partialview consist of a table with multiple rolls.

I am not able to get the collection of data selected by the user in the partial view (table )in my controller.

My Controller

[HttpGet]
    public ActionResult ApproveLaysheet()
    {
        LaySheetShortageViewModel mdl = new LaySheetShortageViewModel();
        ViewBag.AtcID = new SelectList(db.AtcMasters.Where(o => o.IsClosed == "N"), "AtcId", "AtcNum");
        return View(mdl);
    }
      [HttpGet]
    public PartialViewResult GetRollView(decimal[] SelectedOurStyle)
    {
        LaySheetShortageViewModel model = new LaySheetShortageViewModel();        
        LaysheetRollRepository lyipores = new LaysheetRollRepository();
        model.rolldetailcollection= lyipores.getlaysheetRollData(SelectedOurStyle);
        return PartialView("LaySheetRollView",model);
    }
[HttpPost]
    public ActionResult ApproveLaysheet(LaySheetShortageViewModel Model)
    {      // not gretting the value of rolldetailcollection here
        return View();
    }

My View

    @model ArtWebApp.Areas.ArtMVC.Models.ViewModel.LaySheetShortageViewModel
<script type="text/javascript">
    $(document).ready(function () {      
        $("#Show").click(function (e, params) {          
            debugger;
            var SelectedOurStyle = new Array();
            SelectedOurStyle = $("#LaySheetID").chosen().val();            
            if (SelectedOurStyle != null)
            {
            $.ajax({
                    url: "@Url.Action("GetRollView", "ApproveLaysheet")",
                    traditional: true,
                    data: { 'SelectedOurStyle': SelectedOurStyle },
                    type: "GET",
                    success: function (fooBarHTML) {
                        $("#output").html(fooBarHTML);
                    },
                    error: function (xhr, status, errorThrown) {
                        //...
                    }
                });          

         }

        });

    });

</script>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>SampCutReqMaster</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            <div class="row">
                <div  class="col-md-2">
                    @Html.Label("Atcc#", new { @class = "control-label col-md-2" });
                </div>
                <div class="col-md-10">
                    @Html.DropDownList("AtcID", null, htmlAttributes: new { @class = "chosen-select form-control" })                
                </div>
            </div>         

        </div>


        <div class="form-group">
            <div class="row">
                <div class="col-md-2">
                    @Html.Label("OurStyle#", new { @class = "control-label col-md-2" });
                </div>
                <div class="col-md-10">
                    @Html.DropDownList("OurStyleID", new MultiSelectList(string.Empty, "Value", "Text") , null, htmlAttributes: new { @class = "chosen-select form-control", @multiple = "multiple" } )

                </div>

            </div>         

        </div>

        <div class="form-group">
            <div class="row">
                <div class="col-md-2">
                    @Html.Label("LaySheet#", new { @class = "control-label col-md-2" });
                </div>
                <div class="col-md-10">
                    @Html.DropDownList("LaySheetID", new MultiSelectList(string.Empty, "Value", "Text"), null, htmlAttributes: new { @class = "chosen-select form-control", @multiple = "multiple" })

                </div>
            </div>
        </div>

        <div id='output' class="">
            <!-- Partialview Comes here -->
        </div>


</div>
}

My Partial View

@using HtmlHelpers.BeginCollectionItem
@model ArtWebApp.Areas.ArtMVC.Models.ViewModel.LaySheetShortageViewModel
<script src="~/JQuery/GridJQuery.js"></script>
<script>

</script>
<div class="container">

    <table class="table table-bordered table-striped table-responsive">
        <tr>
            <th>
                @Html.CheckBox("SelectAll")
            </th>
            <th>
                @Html.DisplayNameFor(model => model.approvelaysheetModel.LaySheetDet_PK)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.approvelaysheetModel.LayCutNum)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.approvelaysheetModel.RollNum)
            </th>          
     </tr>
        @if (Model != null)
        {
        for (int i = 0; i < Model.rolldetailcollection.Count; i++)
            {
                using (Html.BeginCollectionItem("rolldata"))
                {
                <tr>
                    <td>
                        @Html.EditorFor(modelItem => Model.rolldetailcollection[i].IsSelected, new { @onclick = "Check_ClickNew(this)" })
                    </td>
                    <td>
                        @Html.EditorFor(modelItem => Model.rolldetailcollection[i].LaySheetDet_PK)
                        @Html.HiddenFor(model => Model.rolldetailcollection[i].LaySheetDet_PK, new { htmlAttributes = new { @class = "form-control" } })
                   </td>
                    <td>
                        @Html.DisplayFor(modelItem => Model.rolldetailcollection[i].LayCutNum)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => Model.rolldetailcollection[i].RollNum)
                    </td>                  
                  </tr>
                }
            }

        }
       </table>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input id="Submit" type="submit" value="Submit Fabric request" class="btn btn-default show" />
        </div>
    </div>
</div>

My viewModals

 public class ApprovelaysheetModel
    { 
        public Decimal ApprovelaysheetModelID { get; set; }

        [Display(Name ="ID")]
        public Decimal LaySheetDet_PK { get; set; }
        public Boolean IsSelected { get; set; }
        public Decimal LaySheet_PK { get; set; }
     }

    public class LaySheetShortageViewModel
    {
        [Key]
        [Display(Name = "ID")]
        public Decimal ShortageID { get; set; }
        public int Location_pk { get; set; }
        public int Atcid { get; set; }
        public int OurstyleID { get; set; }        }
        public List<ApprovelaysheetModel> rolldetailcollection { get; set; }
    }

Can anyone suggest whats my mistake or any better method for doing this dataentry as Iam new to MVC

Sreenath Ganga
  • 696
  • 4
  • 19
  • 48
  • 1
    There are multiple issues with your code, but the reason your collection dos not bind is because your using `BeginCollectionItem()` to prefix your `name` attributes with `rolldata[xxx]` which has no relationship to your model. Why are you using `BeginCollectionItem()` (that is only for dynamically adding and deleting items from your collection which you do not appear to be doing)? And if you did want that functionality, the your do not use a `for` loop –  Aug 02 '17 at 10:47
  • Hi Step I had tried previously without begin collection and just used foreach (var item in Model.rolldetailcollection) but it didnt helped i was getting rolldetail collection as null now with begin collection it shows the count correctly but the items inside are not binded. I need to get all the rows of the table in my postback. – Sreenath Ganga Aug 02 '17 at 11:01
  • 1
    You cannot use a `foreach` loop (although you need to if your using `BeginCollectionItem` but that's a different issue). You need a `for` loop or `EditorTemplate` (refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943)). If you not dynamically adding and removing items from the collection in the view, then just remove the `using (Html.BeginCollectionItem("rolldata"))` line of code and it will bind correctly –  Aug 02 '17 at 11:04
  • 1
    But there are a lot or unrelated issues with your code. Suggest you study the code in [this DotNetFiddle](https://dotnetfiddle.net/1bPZym) for how to generate cascading dropdownlists. And also [this answer](https://stackoverflow.com/questions/40725358/why-does-the-dropdownlistfor-lose-the-multiple-selection-after-submit-but-the-li/40732481#40732481) for why you must use `ListBoxFor()` not `DropDownListFor()` when creating a ` –  Aug 02 '17 at 11:10
  • You are great dude you are genius.... You solved My issue... can you post something on answer so that I can mark it as solved and will help somebody in future – Sreenath Ganga Aug 02 '17 at 11:12
  • Iam using jquery choosen to manipulate dropdownlist... also i had posted the part of code req to understand anyway i will check with listfor – Sreenath Ganga Aug 02 '17 at 11:14
  • 1
    Sure, but it will be 30 min or so. And I'll add a few more notes (your view model should be changed to allow strong typed binding). And I know your using `chosen`, but that makes no difference –  Aug 02 '17 at 11:15
  • Thanks Will Take care in future – Sreenath Ganga Aug 02 '17 at 11:17
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/150818/discussion-between-stephen-muecke-and-sreenath-ganga). –  Aug 02 '17 at 11:35

1 Answers1

0

Your use of BeginCollectionItem() inside the for loop is prefixing your name attributes so that they no longer relate to your models properties. Instead of generating

<input type="checkbox" name="rolldetailcollection[0].IsSelected" ... />

your now generating

<input type="checkbox" name="rolldata[####].rolldetailcollection[0].IsSelected" ... />

where #### is a Guid.

Remove the BeginCollectionItem() code so that your loop is

for (int i = 0; i < Model.rolldetailcollection.Count; i++)
{
    <tr>
        <td>
            @Html.EditorFor(m => m.rolldetailcollection[i].IsSelected, new { @onclick = "Check_ClickNew(this)" })
         </td>
         <td>
             @Html.EditorFor(m => m.rolldetailcollection[i].LaySheetDet_PK) 
             // Note there is no point adding html attributes for a hidden input
             @Html.HiddenFor(m => m.rolldetailcollection[i].LaySheetDet_PK)
         </td>
         ....                 
    </tr>
}

Note that the BeginCollectionItem() method is used when you want to dynamically add and remove items from a collection in the view in conjunction with javascript/ajax (refer this answer for an example). If you do want to do that, then you need to create a partial view (say) _ApprovelaysheetModel.cshtml for the model

@model ApprovelaysheetModel
// Note the name needs to match the collection property name
@using (Html.BeginCollectionItem("rolldetailcollection"))
{
    ....
    @Html.EditorFor(m => m.LaySheetDet_PK)
    ....
}

and then in the main view you use a foreach loop

@foreach(var item in Model.rolldetailcollection)
{
    @Html.Partial("_ApprovelaysheetModel", item)
}