使用 ViewModels 向控制器提交带有动态添加的局部视图的数据不工作
Submit data with dynamically added partial view to the controller using ViewModels not working
我正在向查询表单动态添加项目。为 adding/deleting 项目使用部分视图,但在提交主视图时未绑定值。我的问题是如何做同样的事情。
检查了几个类似的问题here and 但找不到缺少的内容。
使用 2 个 ViewModels,用于主视图 (Enquiry) 和部分视图 (LineItems),并使用 BeginCollectionItem 动态添加项目。
代码:
视图模型
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 ),以便我可以将它插入到数据库中。
感谢您的耐心和时间。
您的集合 属性 的名称是 LineItems
,因此生成其控件的代码需要是
@using (Html.BeginCollectionItem("LineItems")) // not ..("ItemList")
{
....
}
以便它生成带有 name="LineItems[xxxx].ItemDesc"
等的输入,而不是您当前使用的生成 name="ItemList[xxxx].ItemDesc"
(其中 xxxx
是 Guid
)
作为旁注,如果 ModelState
无效,则 POST 方法中的代码将抛出异常,因为您 return 视图并且没有重新填充 IEnumerable<SelectListItem> Clients
属性。详细解释请参考。
此外,添加项目的脚本的最后两行 ($('form').data('validator', null); $.validator.unobtrusive.parse($('form'));
应该被删除(重新解析验证器是昂贵的,而且你做了两次 - 在添加 html (上面的 2 行)和一次添加 html
我正在向查询表单动态添加项目。为 adding/deleting 项目使用部分视图,但在提交主视图时未绑定值。我的问题是如何做同样的事情。
检查了几个类似的问题here and
使用 2 个 ViewModels,用于主视图 (Enquiry) 和部分视图 (LineItems),并使用 BeginCollectionItem 动态添加项目。
代码:
视图模型
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 ),以便我可以将它插入到数据库中。 感谢您的耐心和时间。
您的集合 属性 的名称是 LineItems
,因此生成其控件的代码需要是
@using (Html.BeginCollectionItem("LineItems")) // not ..("ItemList")
{
....
}
以便它生成带有 name="LineItems[xxxx].ItemDesc"
等的输入,而不是您当前使用的生成 name="ItemList[xxxx].ItemDesc"
(其中 xxxx
是 Guid
)
作为旁注,如果 ModelState
无效,则 POST 方法中的代码将抛出异常,因为您 return 视图并且没有重新填充 IEnumerable<SelectListItem> Clients
属性。详细解释请参考
此外,添加项目的脚本的最后两行 ($('form').data('validator', null); $.validator.unobtrusive.parse($('form'));
应该被删除(重新解析验证器是昂贵的,而且你做了两次 - 在添加 html (上面的 2 行)和一次添加 html