呈现局部视图不匹配模型呈现局部视图不匹配模型(Rendered partial view does

2019-05-12 13:00发布

所以,我已经写了一些代码,允许添加和从集合动态在ASP.NET MVC中使用AJAX移除元素。 添加新的项目,如预期的收集工作,但除去没有。 如预期(合适的项目被索引中删除)的模型集合更新,但呈现的HTML一再表明的最后一个项目已被删除(而不是一个指定索引处)。

举例来说,假设我有以下项目:

  • 酒吧
  • 巴兹

当我点击“删除”旁边名为“foo”的项目,我期望得到的呈现的HTML看起来如下:

  • 酒吧
  • 巴兹

当我通过控制器动作调试,这似乎是如此,因为模型上的名称集合只包含那些项目。 然而,回到我的AJAX的处理程序所提供的HTML是:

  • 酒吧

我想这个问题可能与缓存的事,但没有我试过(OutputCache指令,设置高速缓存:$就假,等)工作。

下面是代码:

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);
   });

});

Answer 1:

这样做的原因是因为你回发你的模型,以及模型的值被添加到ModelStateDefaultModeBinder 。 所述HtmlHelper生成表单控件的方法(你的情况@Html.EditorFor(m => m.Names, "Names")使用来自值ModelState如果它们存在(而该实际属性值)。 这样做的原因行为在第二部分解释这个答案 )。

在你的情况ModelState

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

所以即使更新的模型您在返回只包含Name[0]: BarName[1]: Baz ,该EditorFor()方法,在第一次迭代将检查ModelState的值Name[0]发现它的存在和输出Foo

你可以通过使用解决这个ModelState.Clear()返回视图(虽然正确的做法是使用PRG模式)之前,但在你的情况下,这一切都不似乎有必要,尤其是具有回发整个模型。 你可以简单地回来后该项目的索引或Name值,(或者如果它是一个复杂的对象,那么ID值),删除该项目,并返回一个JsonResult表示成功与否。 然后在阿贾克斯success的回调,从DOM中移除该项目。



文章来源: Rendered partial view does not match model