如果模型状态无效,则不保留部分视图

时间:2017-04-18 00:01:21

标签: asp.net-mvc

我是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; }
    }

我错过了什么?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

您的主视图需要包含一个循环,以便为任何现有的QuoteDetail(包括您动态添加的那些)生成html。

在您的GET方法或QuoteViewModel的默认构造函数中,请确保将QuoteDetail初始化为新集合,使其不是null。然后在视图中,添加以下代码

@foreach(var detail in Model.QuoteDetail)
{
    @Html.Partial("EditQuoteDetail", detail)
}

作为旁注,您应该使用QuoteDetail的视图模型,它不应包含属性QuoteId