使用ViewModel无效工作,使用动态添加的局部视图向控制器提交数据

时间:2017-09-19 08:48:03

标签: c# asp.net-mvc-5 begincollectionitem

我正在将动态项添加到“查询”表单中。使用部分视图来添加/删除项目,但在提交主视图时,未绑定值。我的问题是如何做同样的事情。

检查了几个类似的问题herehere但是找不到遗漏的内容。

使用2个ViewModel,用于主视图(查询)和部分视图(LineItems),并使用BeginCollectionItem动态添加项目。

代码:

的ViewModels

public class EnquiryVM
    {
        public int ID { get; set; }

        [Required]
        public string EnquiryNumber { get; set; }
        public int ClientID { get; set; }
        public IEnumerable<SelectListItem> Clients { get; set; }
        public Client Client { get; set; }
        public int ItemID { get; set; }
        public List<EnquiryLineItem> LineItems { get; set; }

    }
 public class EnquiryLineItemVM
    {
        public int ID { get; set; }
        [Required]
        public string ItemDesc { get; set; }
        public int Quantity { get; set; }
        public int ManufacturerId { get; set; }
        public IEnumerable<SelectListItem> ManufacturerList { get; set; }
    }

观点: 主:

@model ViewModel.EnquiryVM

@using (Html.BeginForm("Create", "Enquiries", FormMethod.Post))
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">

        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })



        <div class="form-group">
            @Html.LabelFor(model => model.EnquiryNumber, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-3">
                @Html.EditorFor(model => model.EnquiryNumber, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.EnquiryNumber, "", new { @class = "text-danger" })
            </div>
        </div>





        <div class="form-group">
            @Html.LabelFor(model => model.ClientID, "Client", htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-3">

                @Html.DropDownListFor(u => u.ClientID, (IEnumerable<SelectListItem>)Model.Clients, "--Select--")
                @Html.ValidationMessageFor(model => model.ClientID, "", new { @class = "text-danger" })
            </div>
        </div>

         <div id="LineItems">
          //  @using (Html.BeginForm()) // do we require again here since this will be like nested form? tested commenting still not working
           // {
                <div id="editorRowsLineitems">
                    @foreach (var item in Model.LineItems)
                    {
                        @Html.Partial("_CreateEnquiryItem", item)
                    }
                </div>
                @Html.ActionLink("Add Items", "CreateLineItem", null, new { id = "addItem", @class = "button" });
          //  }
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
    $(function () {
        $('#addItem').on('click', function () {
            $.ajax({
                url: '@Url.Action("CreateLineItem")',
                    cache: false,
                    success: function (html) {
                        $("#editorRowsLineitems").append(html);

                        $("form").removeData("validator");
                        $("form").removeData("unobtrusiveValidation");
                        $.validator.unobtrusive.parse("form");
                    }
                });
                return false;
            });
        $('#editorRowsLineitems').on('click', '.deleteRow', function () {
                $(this).closest('.editorRow').remove();
            });
        $('form').data('validator', null);
        $.validator.unobtrusive.parse($('form'));
    });


</script>
}

局部视图:

@model ViewModels.EnquiryLineItemVM

<div class="editorRow">
    @using (Html.BeginCollectionItem("ItemList"))
    {
        <table class="table">

            <tr>
                <td>
                    @Html.EditorFor(model => model.ItemDesc)

                </td>
                <td>
                    @Html.EditorFor(model => model.Quantity)

                </td>

                <td>
                    @Html.DropDownListFor(model => model.ManufacturerId, Model.ManufacturerList, "--Please Select--")

                </td>
                <td>

                    <a href="#" class="deleteRow">Delete</a>
                </td>
            </tr>
        </table>

    }

控制器:

 public ActionResult Create()
        {
            var viewModel = GetAllCategories();
            return View(viewModel);
        }
  private EnquiryVM GetAllCategories()
        {
            var model = new EnquiryVM();
            var clients = db.Clients.ToList();
            model.Clients = clients.Select(s => new SelectListItem
            {
                Value = s.ID.ToString(),
                Text = s.Name
            });

            var LineItems = new List<EnquiryLineItem>();
            model.LineItems = LineItems;

           return model;
        }
 [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create( EnquiryVM enquiryVM)
        {
            var enquiry = new Enquiry();
            enquiry.EnquiryNumber = enquiryVM.EnquiryNumber;
            enquiry.ClientID = enquiryVM.ClientID;
            enquiry.EnquiryLineItems = enquiryVM.LineItems; //line items are null
            if (ModelState.IsValid)
            {
                db.Enquiries.Add(enquiry);
                enquiryVM.ID = enquiry.ID;
                foreach (var item in enquiry.EnquiryLineItems)
                {
                    item.EnquiryID = enquiryVM.ID;
                    db.EnquiryLineItems.Add(item);
                }

                db.SaveChanges();
                return RedirectToAction("Index");
            }

            var viewModel = GetAllCategories();
            return View(enquiryVM);
        }

如何将动态添加的行的值映射到ViewModel(EnquiryVM),以便我可以将其插入到数据库中。 感谢您的耐心和时间。

1 个答案:

答案 0 :(得分:1)

您的集合属性的名称是LineItems,因此生成其控件的代码需要

@using (Html.BeginCollectionItem("LineItems")) // not ..("ItemList")
{
    ....
}

以便使用name="LineItems[xxxx].ItemDesc"等生成输入,而不是生成name="ItemList[xxxx].ItemDesc"的当前用途(其中xxxxGuid

作为旁注,如果ModelState无效,则POST方法中的代码将抛出异常,因为您返回视图但尚未重新填充IEnumerable<SelectListItem> Clients属性。有关详细说明,请参阅The ViewData item that has the key 'XXX' is of type 'System.Int32' but must be of type 'IEnumerable'

此外,你的脚本最后2行添加项目($('form').data('validator', null); $.validator.unobtrusive.parse($('form'));应该被删除(重新验证验证器是昂贵的,你做两次 - 在你添加html之前一次(上面的2行)和一旦你添加了html