MVC 5 BeginCollectionItem with Partial CRUD

后端 未结 4 1341
夕颜
夕颜 2020-11-30 04:10

I have made changes below to the question, which is still the same but hopefully a lot clearer through the models and in regards to what I want to achieve and where I\'ve co

相关标签:
4条回答
  • 2020-11-30 04:51

    Lets say ClassA is your ViewModel:

    You only need one Partial View or View to Update both:

    e.g. Edit.cshtml

    @model ClassA
    
    @Html.BeginForm(){
    
    @Html.TextBoxFor(m => m.name)
    
    for(int i = 0; i< Model.classB.Count; i++){
    
         @Html.TextBoxFor(m => Model.classB[i].name)
    <button type="button"> Add </button>
    <button type="button"> Remove </button>
    }
    
    <input type="submit"  value = "save"/>
    
    }
    

    Note: In your Partial view you are using foreach loop, The MVC Model Binder Requires the Input fields to be in the format:

    list[0].prop1
    list[0].prop2
    list[0].prop3
    
    list[1].prop1
    list[1].prop2
    list[1].prop3
    

    So for this we use for loop

    Then in controller:

    [HttpPost]
    public ActionResult Edit(ClassA model){
    
    
    // HEre you will see model.ClassB list
    // you can then save them one by one
    
    foreach(var item in Model.classB){
    
    save
    }
    return View(model);
    }
    

    If you want to dynamically Add or Remove Items from the List:

    Create another Partial View classBs:

            @model List<classB>
            <div id="lists">
                foreach (var contact in Model)
                {
                   @Html.Partial("ClassBRow", contact)
                }
        </div>
    
    <button data-action-url="@Url.Action("ClassBRow","CONTROLLER")" class="btn btn-primary pull-right" id="addItem">Add</button>
    
    <script>
     $("#addItem").click(function () {
                var btn = $(this);
                $.ajax({
                    url: btn.data('action-url'),
                    success: function (html) {
                        $("#lists").append(html);
                    }
                });
                return false;
            });
    
    </script>
    

    Create another Partial View: ClassBRow.cshtml:

    @model classB
    
     using (Html.BeginCollectionItem("classB"))
        {
                @Html.HiddenFor(m => m.isDeleted, new { data_is_deleted = "false" })
                @Html.TextBoxFor(m => Model.name, new { @class = "form-control" })
    
    <span class="glyphicon glyphicon-trash" data-action="removeItem" title="remove" style="cursor:pointer"></span>
    
        }
    

    In your controller:

    public ActionResult ClassBRow()
    {
        return PartialView(new classB());
    }
    

    AND Edit.cshtml becomes:

        @model ClassA
    
        @Html.BeginForm(){
    
        @Html.TextBoxFor(m => m.name)
    
    @Html.Partial("classBs", model.classB)
    
        <input type="submit"  value = "save"/>
    
        }
    
    0 讨论(0)
  • 2020-11-30 04:51

    Treat the views as independent. If your partial view was a full view, you would pass it a IEnumerable<ClassB>

    so render with:

     @Html.Partial("ClassBView", Model.ClassB)
    

    Also, you can't use foreach with EditorFor as there is insufficient information to create a name based on the index. Use a normal for loop instead. The expression parser can then convert it to name="name[1]" etc as the index is available in the expression:

    @model IEnumerable<Project.Models.ClassB>
    
    @if(Model != null)
    {
        for (int i = 0; i < Model.Count; i++)
        {
        <tr>
            <td>
                @Html.EditorFor(modelItem => Model[i].Name)
                <input type="button" value="Clear" />
                <input type="submit" value="Create" />
            </td>
        </tr>
        }
    }
    

    There is more missing from your example (what Clear and Create connect to for instance), so if you can provide the rest of your controller code I will expand this.

    0 讨论(0)
  • 2020-11-30 04:52

    You can use (EditorTemplates) to view (ClassB) as following:

    1- Create folder named (EditorTemplates) under the (Views/Home) folder (Assuming your controller name is Home):

    2- Under the created (EditorTemplates) folder, create a view named (ClassB)

    enter image description here

    and add the following template for the (ClassB) view:

    @model Project.Models.ClassB
    @if(Model != null)
    {
    
        <tr>
            <td>
                @Html.EditorFor(modelItem => Model.Name)
                <input type="button" value="Clear" />
                <input type="submit" value="Create" />
            </td>
        </tr>
    
    }
    

    and (ClassAView) should be as following:

    @model Project.Models.ClassA
    
    <tr>
    <td>
    @Html.EditorFor(m => m.name)
    </td>
    <td>
    @Html.EditorFor(m => m.classB);
    </td>
    </tr>
    

    The editor will automatically iterate through the list of objects rendering the view for each of them.

    0 讨论(0)
  • 2020-11-30 05:04

    You do not need to use BeginCollectionItem in order to achieve this. From having to look into it myself and trying to use it for a similar issue, it appears it was created for problems of this nature with earlier versions of MVC.

    Use Partial Views to display and update the list. One partial view to display and iterate through the list of objects, and another to create a new object which upon post back to update the list will show the newly created object in the partial view with the list.

    I posted a similar question on here which should solve your issue, click here

    Hope this helps.

    Update The reason your delete doesn't work is because you can't call JS from Partial View, put it in the main view (@section Script). Also I think you got a bit muddled with your class and id keywords in your divs, have a look below.

    So you should have:

    Partial View

    @model MvcTest.Models.Employee
        @using (Html.BeginCollectionItem("Employees"))
        {
            <div id="employeeRow" class="employeeRow">
                @Html.LabelFor(m => m.Name)
                @Html.EditorFor(m => m.Name)
    
                @Html.LabelFor(m => m.Telephone)
                @Html.EditorFor(m => m.Telephone)
    
                @Html.LabelFor(m => m.Mobile)
                @Html.EditorFor(m => m.Mobile)
    
                @Html.LabelFor(m => m.JobTitle)
                @Html.EditorFor(m => m.JobTitle)
    
                <a href="#" id="deleteRow" class="deleteRow" onclick="deleteFunction()">Delete</a>
            </div>
        }
    

    Main View

        @model MvcTest.Models.Company
    @{
        ViewBag.Title = "Index";
        Layout = "~/Views/Shared/_Layout.cshtml";
    }
    
    <h2>Company</h2>
    <div>
        @Html.LabelFor(m => m.Name)
        @Html.EditorFor(m => m.Name)
    </div>
    <fieldset>
        <legend>Employees</legend>
        <div id="new-Employee">
            @foreach (var Employee in Model.Employees)
            {
                Html.RenderPartial("_Employee", Employee);
            }
        </div>
        <div>
            <input type="button" id="addemployee" name="addemployee" value="Add Employee"/>
            <br/>
        </div>
        <br/>
        @section Scripts
        {
            <script type="text/javascript">
                $('#addemployee').on('click', function () {
                    $.ajax({
                        async: false,
                        url: '/Company/AddNewEmployee'
                    }).success(function (partialView) {
                        $('#new-Employee').append(partialView);
                    });
                });
    
                $("#deleteRow").live("click", function () {
                    $(this).parents("#employeeRow:first").remove();
                    return false;
                });
            </script>
        }
    </fieldset>
    <div>
        <input type="submit" value="Submit" />
    </div>
    
    0 讨论(0)
提交回复
热议问题