Asp.net mvc For循环中的MVC Ajax表单

Asp.net mvc For循环中的MVC Ajax表单,asp.net-mvc,asp.net-ajax,ajax.beginform,Asp.net Mvc,Asp.net Ajax,Ajax.beginform,我在For循环中使用Ajax.BeginForm,它允许我为For循环中的每个项目发布到控制器。最初,for循环在页面加载时正确呈现每个项目。 当控制器处理了从Ajax.beginnform正确填充的传入视图模型后,该方法将新生成的视图模型发送回视图,但是我的For循环中的每个项目现在都是重复的,并且所有文本框现在都具有提交的视图模型的值 非常困惑如何正确构造此代码,我需要提交基于ajax和部分视图的工作。我确实考虑过使用JQuery提交,但担心会丢失AntiForgeryToken,而且Aja

我在For循环中使用Ajax.BeginForm,它允许我为For循环中的每个项目发布到控制器。最初,for循环在页面加载时正确呈现每个项目。 当控制器处理了从Ajax.beginnform正确填充的传入视图模型后,该方法将新生成的视图模型发送回视图,但是我的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>
    }
}
@model Namespace.Models.MyParentViewModel
@对于(int i=0;i
控制器

[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
}
[HttpPost]
[ValidateAntiForgeryToken]
[操作名称(“保存项”)]
公共操作结果保存项(MyItemViewModel MIM,字符串命令)
{
if(ModelState.IsValid)
{
#做些逻辑分析
}
//返回新填充的MyViewModel和更新的MIM。
var model=PopulateMyParentViewModel();
返回PartialView(“MyPartialView”,model);
}
私有MyParentViewModel PopulateMyParentViewModel()
{
列表项=新列表();
foreach(enity.items.OrderBy(p=>p.ID.ToList()中的var item)
{
var ExistingItem=新的MyItemViewModel
{
ID=item.ID,
TheName=item.TheName
};
添加(MyItemViewModel);
}
MyParentViewModel.Items=lstItems;
返回MyParentViewModel
}
我不确定代码中的“养老金”是什么,我猜它是一个围绕循环生成的每个表单的div?如果是这样,您的问题如下:

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

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

解决方案

  • 如果重新生成项目以仅发回一条记录而不是全部记录,则只需使用(…)块在
    周围添加唯一标识(=具有唯一的
    id
    属性)
    元素,将
    InsertionMode
    设置为
    InsertionMode=InsertionMode.Replace
    并将
    UpdateTargetId
    属性设置为该
    id
    ,如下所示:

    <div id="record-@i">    
    @using (Ajax.BeginForm("SaveItem", "Controller", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "record-" + i.ToString(), InsertionMode = InsertionMode.Replace }))
    {
        // ...
    }
    </div>
    
    public ActionResult UpdateRecord(Int64 id)
    {
      var _record = Repository.Get(id);
      // logic to hide and update record
      return PartialView("TableRow_Partial",_record);
    }
    
    假设Ajax请求所做的更改是,无论何时隐藏记录,都会返回一个表行,其中的一个按钮现在显示“show”而不是“hide”,并返回与触发请求的按钮所属的人员相关的相同数据。 然后,当您发出直接(=非ajax,当您直接导航到页面时)请求时,您可以执行以下操作:

    @model PeopleCollection
    ...
    <table>
    <thead>
      <tr>
        <td>Name</td>
        <td>Age</td>
        <td>Salary</td>
        <td>Hide</td>
      </tr>
    </thead>
    <tbody>
      @foreach (Person record in Model) {
        @Html.Partial("TableRow_Partial",record)
      }
    </tbody>
    
    为此,必须将
    InsertionMode
    设置为
    InsertionMode.ReplaceWith
    。所有这一切都是因为,当您发送一个ajax请求以仅使用一条记录执行某项操作时,您只需刷新一项——触发ajax调用的一项,然后您只需返回新行(一行!),并将旧的一行替换为新的一行


    如果您真的希望每次处理记录时都将整个项目集合发送回客户机,只需将整个呈现的表发送给客户机,并以类似的方式将旧表替换为新表。

    谢谢,但对返回模型有点混淆。如果我使用您的解决方案中的代码,我可以将单个模型传递给控制器并在数据库中更新该模型,但是当控制器返回项目列表时,该列表将替换记录中的单个行-@I将替换for循环迭代中使用的整个列表,并且仍然会导致重复。“pensions”实际上是包裹整个局部视图的div,因为循环在其中。
    @model Person
    @{
      AjaxOptions opts = new AjaxOptions() {
        UpdateTargetId = "person-row-" + Model.Id.ToString(),
        InsertionMode = InsertionMode.ReplaceWith
        // etc
      };
    }
    ...
    <tr id="person-row-@Model.Id">
      <td>@Model.Name</td>
      <td>@Model.Age</td>
      <td>@Model.Salary</td>
      <td>
        <!-- configure the BeginForm(..) call with the action name and a routeValue anonymous object as "new { id = Model.Id}" -->
        @using (Ajax.BeginForm(...)) {
          <input type="submit" value="@(Model.IsHidden ? "Show" : "Hide")" />
        }
      </td>
    </tr>
    
    public ActionResult UpdateRecord(Int64 id)
    {
      var _record = Repository.Get(id);
      // logic to hide and update record
      return PartialView("TableRow_Partial",_record);
    }