我正在将动态项添加到“查询”表单中。使用部分视图来添加/删除项目,但在提交主视图时,未绑定值。我的问题是如何做同样的事情。
检查了几个类似的问题here和here但是找不到遗漏的内容。
使用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),以便我可以将其插入到数据库中。 感谢您的耐心和时间。
答案 0 :(得分:1)
您的集合属性的名称是LineItems
,因此生成其控件的代码需要
@using (Html.BeginCollectionItem("LineItems")) // not ..("ItemList")
{
....
}
以便使用name="LineItems[xxxx].ItemDesc"
等生成输入,而不是生成name="ItemList[xxxx].ItemDesc"
的当前用途(其中xxxx
是Guid
)
作为旁注,如果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