我是MVC的新手。我有一个父视图,使用户可以为客户创建报价。 AJAX链接“添加产品”加载部分视图“EditQuoteDetail”,使用户可以将产品添加到Quote。问题是如果ModelState在POST上无效(假设用户忘记输入所需的电话号码),则产品的部分视图不会返回到视图。如何将QuoteDetails返回给用户?
以下是主要观点:
@model CMSUsersAndRoles.Models.QuoteViewModel
@{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@Scripts.Render("~/Scripts/jquery.unobtrusive-ajax.min.js")
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="~/Scripts/jquery.mask.min.js"></script>
<h2>Create</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Quote</h4>
<hr />
<div class="form-group">
<div class="col-md-10">
@Html.HiddenFor(model => model.QuoteId)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Company, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(model => model.CustomerId, new SelectList(ViewBag.Customers, "CustomerId", "Company"), "---Select one---", new { style = "width: 300px !important", htmlAttributes = new { @class = "company" } });
@Html.HiddenFor(model => model.Company, new { @class = "companyName" })
@Html.ValidationMessageFor(model => model.Company, "", new { @class = "text-danger" })
</div>
</div>
... //other Quote fields
<div class="form-group">
@Html.LabelFor(model => model.QuoteDetail, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10" id="QuoteDetails">
@Html.ValidationMessageFor(model => model.QuoteDetail, "", new { @class = "text-danger"})
@Ajax.ActionLink("Add product", "AddProduct", "QuoteViewModel", new { quoteId = Model.QuoteId, quoteDetailId = (Model.QuoteDetail.Count + 1) }, new AjaxOptions
{
UpdateTargetId = "QuoteDetails",
InsertionMode = InsertionMode.InsertBefore
})
</div>
以下是部分视图:
@model CMSUsersAndRoles.Models.QuoteDetail
@{
ViewBag.Title = "EditQuoteDetail";
Layout = null;
}
<div id="row" class="row">
<table>
@using (Html.BeginCollectionItem("quoteDetail"))
{
<tr>
@Html.HiddenFor(model => model.QuoteId, new { htmlAttributes = new { @class = "form-control" } })
@Html.HiddenFor(model => model.QuoteDetailId, new { htmlAttributes = new { @class = "form-control" } })
@Html.EditorFor(model => model.SKU, new { htmlAttributes = new { @readonly = "readonly", @id = "SKU", @class = "form-control", style = "width: 100px" } })
@Html.DropDownListFor(model => model.ProductId, new SelectList(ViewBag.ProductData, "ProductId", "Name"), "---Select one---", new { style = "width: 300px !important", required = "required", htmlAttributes = new { @id = "ProductName", @class = "ProductList" } })
@Html.HiddenFor(model => model.ProductName)
@Html.EditorFor(model => model.Amount, new { htmlAttributes = new { @id = "Amt", @class = "form-control amount", style = "width: 95px" } })
@Html.EditorFor(model => model.ListPrice, new { htmlAttributes = new { @readonly = "readonly", @id = "LPrce", @class = "form-control listprice", style = "width: 95px" } })
@Html.EditorFor(model => model.Discount, new { htmlAttributes = new { @id = "TotalDiscount", @class = "form-control discount", style = "width: 100px" } })
@Html.EditorFor(model => model.Price, new { htmlAttributes = new { @readonly = "readonly", @id = "FinalPrce", @class = "form-control price", style = "width: 100px" } })
@Ajax.ActionLink(" ", "DeleteProduct", "QuoteViewModel", new { quoteId = Model.QuoteId, quoteDetailId = (Model.QuoteDetailId) },
new AjaxOptions
{
HttpMethod = "POST",
Confirm = "Are you Sure You Want to Delete " + Model.ProductName,
OnSuccess = "RemoveRow"
},
new { @class = "btn btn-danger glyphicon glyphicon-trash" })
</tr>
}
</table>
</div>
这是POST:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(QuoteViewModel qvm)
{
if (qvm.QuoteDetail == null)
{
qvm.QuoteDetail = new List<QuoteDetail>();
qvm.QuoteDetail.Add(new QuoteDetail() { QuoteId = qvm.QuoteId, QuoteDetailId = (qvm.QuoteDetail.Count + 1) });
var customerList = db.Customers.ToList();
ViewBag.Customers = customerList;
return View(qvm);
}
if (ModelState.IsValid)
{
... //process
return RedirectToAction("Index");
}
var customers = db.Customers.ToList();
ViewBag.Customers = customers;
return View(qvm);
}
以下是加载局部视图的代码:
public ActionResult AddProduct(int quoteId, int quoteDetailId)
{
var items = db.Products.ToList();
ViewBag.ProductData = items;
return PartialView("EditQuoteDetail", new QuoteDetail { QuoteId = quoteId, QuoteDetailId = quoteDetailId });
}
以下是ViewModel的相关部分:
public class QuoteViewModel
{ // Columns from QuoteDetail table
[Required(ErrorMessage ="Please add product(s) to quote ")]
[Display(Name = "Quote Detail")]
public List<QuoteDetail> QuoteDetail { get; set; }
}
我错过了什么?任何帮助将不胜感激。
答案 0 :(得分:1)
您的主视图需要包含一个循环,以便为任何现有的QuoteDetail
(包括您动态添加的那些)生成html。
在您的GET方法或QuoteViewModel
的默认构造函数中,请确保将QuoteDetail
初始化为新集合,使其不是null
。然后在视图中,添加以下代码
@foreach(var detail in Model.QuoteDetail)
{
@Html.Partial("EditQuoteDetail", detail)
}
作为旁注,您应该使用QuoteDetail
的视图模型,它不应包含属性QuoteId