For循环中的MVC Ajax表单

时间:2015-01-23 17:29:55

标签: asp.net-mvc asp.net-ajax ajax.beginform

我在For循环中使用Ajax.BeginForm,允许我在for循环中向控制器发布每个项目。最初,for循环在页面加载时正确呈现每个项目。 当控制器处理了从Ajax.BeginForm中正确填充的传入View模型时,该方法将新生成的视图模型发送回View,但是我的For循环中的每个项目现在都是重复的,并且所有文本框现在都有提交的视图模型的值。

如何正确构建此代码非常困惑,我需要提交基于ajax和部分视图的工作。我确实看过使用JQuery提交,但是担心我可能会丢失AntiForgeryToken并且Ajax.BeginForm是一种更优雅的方法。任何帮助非常感谢。很高兴也提供更多信息。

查看

@model Namespace.Models.MyParentViewModel
@for (int i = 0; i < Model.Items.Count; i++)
{
    using (Ajax.BeginForm("SaveItem", "Controller", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "pensions" }))
    {
      @Html.AntiForgeryToken()
      @Html.ValidationSummary()
      <div>
         @Html.Hidden("ID", Model.Items[i].ID)
         @Html.TextBox("TheName", Model.Items[i].TheName, new { @class = "form-control", @id = "item-" + i})
         <input type="submit" value="Save" class="btn save" name="Command" />
      </div>
    }
}

CONTROLLER

[HttpPost]
[ValidateAntiForgeryToken]
[ActionName("SaveItem")]
public ActionResult SaveItem(MyItemViewModel mivm, string Command)
{
   if (ModelState.IsValid)
   {
       #do some logic
   }

   // Return a newly populated MyViewModel with updated mivm.
   var model = PopulateMyParentViewModel();
   return PartialView("_MyPartialView", model);
}

private MyParentViewModel PopulateMyParentViewModel()
{
   List<MyItemsViewModel> lstItems = new List<MyItemsViewModel>();
   foreach (var item in enity.items.OrderBy(p => p.ID).ToList())
   {
     var ExistingItem = new MyItemViewModel
     {
        ID = item.ID,
         TheName = item.TheName
     };

     lstItems.Add(MyItemViewModel);
   }
   MyParentViewModel.Items = lstItems;
   return MyParentViewModel
}

1 个答案:

答案 0 :(得分:1)

我不确定代码中的“养老金”是什么,我猜这是循环生成的每个表单的div?如果是这样,您的问题如下:

  • 首先,如果没有任何项目是相互关联的(也就是说,触发项目的某些更新也会导致另一项更新),则不应浪费资源将整个列表发送回浏览器 - 考虑只发回受影响的“记录”的更新显示,并只用响应更新相应的项目。

  • 导致项目重复的原因:AjaxOptions类有一个属性InsertionMode,我记得,它的默认值是InsertionMode = InsertionMode.InsertAfter,这导致重复项出现。为什么?您向服务器发送Ajax请求,该服务器发送回由整个列表填充的HTML片段,而不是仅发送一个项目,然后浏览器将该片段附加到现有记录。

<强>解决方案

  • 如果您将项目重新制作为仅发回一条记录而不是全部记录,则只需在{{{{{{{} {{{} {{{ {1}}阻止,将id设置为<div>并将using(...)属性设置为InsertionMode的{​​{1}},如下所示:

    InsertionMode=InsertionMode.Replace

    这将导致Ajax响应替换发送请求的容器的内容(通过 contents 我的意思是包装元素本身不会被替换!您需要使用UpdateTargetId来表示该行为。如果你误解了这一点,你最终会在主机容器中倾倒大量的嵌套元素,可能会破坏使用特定选择器的脚本和/或样式。

  • 如果你坚持发回一整套商品,那么只需用id标签包裹for循环,给它<div>,将<div id="record-@i"> @using (Ajax.BeginForm("SaveItem", "Controller", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "record-" + i.ToString(), InsertionMode = InsertionMode.Replace })) { // ... } </div> 设为{ {1}}以及InsertionMode.ReplaceWith的{​​{1}} <div>属性。

---------更新-----------

回答你的评论:

假设您有一个视图 - 为简单起见 - 以表格格式显示记录。然后,结果如下所示:

id

假设您使用Ajax请求更改的内容是,无论何时隐藏记录,您都会发回一个表格行,其中的按钮现在显示“show”而不是“hide”以及有关该属性的相同数据触发请求的按钮。 然后,当你直接(=非ajax,当你直接导航到页面)请求时,你这样做:

InsertionMode

“TableRow_Partial”视图如下所示:

InsertionMode=InsertionMode.Replace

这将简单地将循环结构提取到分离的局部视图中。您的Ajax请求的操作方法处理将简单地返回此视图,填充您已更新的单个记录,如下所示:

UpdateTargetId

要实现此目的,您必须将id设置为<div>。所有这一切都是当你发送ajax请求只用一条记录做一些事情时,你只刷新一个项目 - 触发ajax调用的项目,然后你只需返回新行(一行!)并替换旧的一个有这个新的。

如果您真的想在每次对记录执行操作时坚持将整个项目集合发送回客户端,只需将整个呈现的表格发送到客户端,并将旧表格替换为类似的新表格。方式。