簡體   English   中英

渲染的局部視圖與模型不匹配

[英]Rendered partial view does not match model

因此,我編寫了一些代碼,以允許使用AJAX在ASP.NET MVC中動態地從集合中添加和刪除元素。 將新項目添加到集合中可以按預期工作,但是刪除則不能。 模型集合將按預期進行更新(適當的項目將通過索引刪除),但是呈現的HTML始終顯示最后一個項目已被刪除(而不是指定索引處的項目)。

例如,假設我有以下項目:

  • oo
  • 酒吧
  • 巴茲

當我單擊名為“ Foo”的項目旁邊的“刪除”時,我希望生成的呈現HTML如下所示:

  • 酒吧
  • 巴茲

當我通過控制器操作進行調試時,似乎是這種情況,因為模型上的Names集合僅包含那些項。 但是,返回到我的AJAX處理程序的呈現的HTML是:

  • oo
  • 酒吧

我以為問題可能與緩存有關,但是我沒有嘗試過(OutputCache指令,在$ .ajax中設置cache:false等)正在工作。

這是代碼:

DemoViewModel.cs

namespace MvcPlayground.Models
{
   using System;
   using System.Collections.Generic;
   using System.Linq;
   using System.Text;
   using System.Threading.Tasks;

   public class DemoViewModel
   {
      public List<string> Names { get; set; }

      public DemoViewModel()
      {
         Names = new List<string>();
      }
   }
}

DemoController.cs

這里的明顯問題是在RemoveName方法中。 我可以驗證PartialViewResult的Model屬性是否按我期望的方式反映了集合狀態,但是一旦呈現給客戶端,HTML就會不符合我的期望。

namespace MvcPlayground.Controllers
{
   using MvcPlayground.Models;
   using System;
   using System.Collections.Generic;
   using System.Linq;
   using System.Web;
   using System.Web.Mvc;

    public class DemoController : Controller
    {
        // GET: Demo
        public ActionResult Index()
        {
            var model = new DemoViewModel();
            return View(model);
        }

        [HttpPost]
        public ActionResult AddName(DemoViewModel model)
        {
            model.Names.Add(string.Empty);

            ViewData.TemplateInfo.HtmlFieldPrefix = "Names";
            return PartialView("EditorTemplates/Names", model.Names);
        }

        [HttpPost]
        public ActionResult RemoveName(DemoViewModel model, int index)
        {
           model.Names.RemoveAt(index);

           ViewData.TemplateInfo.HtmlFieldPrefix = "Names";
           var result = PartialView("EditorTemplates/Names", model.Names);
           return result;
        }
    }
}

Names.cshtml

這是我用來渲染名稱列表的編輯器模板。 將新項目添加到集合時,按預期工作。

@model List<string>

@for (int i = 0; i < Model.Count; i++)
{
   <p>
      @Html.EditorFor(m => m[i]) @Html.ActionLink("remove", "RemoveName", null, new { data_target = "names", data_index = i, @class = "link link-item-remove" })
   </p>
}

Index.cshtml

這是加載的初始頁面,這里沒有什么太復雜的。

@model MvcPlayground.Models.DemoViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>


@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

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

       <div class="container-collection" id="names">
         @Html.EditorFor(m => m.Names, "Names")
       </div>
        @Html.ActionLink("Add New", "AddName", "Demo", null, new { data_target = "names", @class = "btn btn-addnew" })

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}

Index.js

該腳本處理對AddName和RemoveName的調用。 這里的一切都按我的預期工作。

$('form').on('click', '.btn-addnew', function (e) {
   e.preventDefault();

   var form = $(this).closest('form');
   var targetId = $(this).data('target');

   var target = form.find('#' + targetId);
   var href = $(this).attr('href');

   $.ajax({
      url: href,
      cache: false,
      type: 'POST',
      data: form.serialize()
   }).done(function (html) {
      target.html(html);
   });
});

$('form').on('click', '.link-item-remove', function (e) {
   e.preventDefault();

   var form = $(this).closest('form');
   var targetId = $(this).data('target');

   var target = form.find('#' + targetId);
   var href = $(this).attr('href');

   var formData = form.serialize() + '&index=' + $(this).data('index');

   $.ajax({
      url: href,
      cache: false,
      type: 'POST',
      data: formData
   }).done(function (html) {
      target.html(html);
   });

});

這樣做的原因是因為您回發了模型,並且模型的值由DefaultModeBinder添加到ModelState 生成表單控件的HtmlHelper方法(在您的情況下為@Html.EditorFor(m => m.Names, "Names") )使用ModelState的值(如果存在)(而不是實際的屬性值)。 此答案的第二部分將解釋這種現象的原因。

在你的情況下, ModelState值是

Name[0]: Foo
Name[1]: Bar
Name[2]: Baz

因此,即使您返回的更新模型僅包含Name[0]: BarName[1]: BazEditorFor()方法在第一次迭代中仍將檢查Name[0]ModelState值,發現它存在並輸出Foo

您可以通過在返回視圖之前使用ModelState.Clear()來解決此問題(盡管正確的方法是使用PRG模式),但是在您的情況下,這似乎沒有必要,尤其是必須回發整個模型。 您可以簡單地回發該項目的索引或Name值(或者,如果它是一個復雜的對象,則返回一個ID值),刪除該項目並返回一個JsonResult指示成功或其他。 然后在ajax success回調中,從DOM中刪除該項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM