如何在MVC 4中使用jQuery更新List

我目前正在尝试使用修改后的索引视图创建设置页面。 目标是用户显示所有设置,并可以在一个视图中更改所有设置,使用一个按钮保存所有设置 。 应使用Ajax更新该设置。

我目前的做法:

视图:

 $(function() { $('#editSettings').submit(function () { if ($(this).valid()) { $.ajax({ url: this.action, type: this.method, data: $(this).serialize(), success: function (result) { alert(result); } }); } return false; }); });  [ ... ] @using (Ajax.BeginForm("Edit", "Settings", new AjaxOptions {UpdateTargetId = "result"}, new { @class = "form-horizontal", @id = "editSettings" } )) { foreach (Setting item in ViewBag.Settings) { @Html.Partial("_SingleSetting", item) }  } 

部分视图加载设置:

  
@Html.EditorFor(model => model.Value) @settingDescription

模型:

 [Table("Settings")] public class Setting { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int SettingId { get; set; } public string Name { get; set; } [Required(AllowEmptyStrings = true)] [DisplayFormat(ConvertEmptyStringToNull = false)] public string Value { get; set; } } 

我使用ViewBag.Settings = _db.Settings.ToList();设置ViewBag ViewBag.Settings = _db.Settings.ToList();

jQuery将Data解析为以下方法:

  [HttpPost] public ActionResult Edit(IList setting) { Console.WriteLine(setting.Count); return Content(""); // Currently for testing purposes only. Breakpoint is set to setting.Count } 

Count抛出错误,因为设置为null 。 我不太确定如何解决这个问题。

有人可以给我一个提示吗?

关于SO的这个主题已经涵盖了在没有Ajax的情况下更新Collection。 但我不明白这一点。

谢谢您的帮助。

您正在使用Ajax.BeginForm并使用jQuery再次激活表单。 这不是必要的。 但是代码的真正问题是部分中输入字段的名称。 您不尊重默认模型绑定器用于绑定到列表的naming convention

我们来看一个完整的例子(为了简单起见,删除所有噪声,例如Entity Framework):

模型:

 public class Setting { public int SettingId { get; set; } public string Name { get; set; } public string Value { get; set; } } 

控制器:

 public class SettingsController : Controller { public ActionResult Index() { // No idea why you are using ViewBag instead of view model // but I am really sick of repeating this so will leave it just that way ViewBag.Settings = Enumerable.Range(1, 5).Select(x => new Setting { SettingId = x, Name = "setting " + x, Value = "value " + x }).ToList(); return View(); } [HttpPost] public ActionResult Edit(IList setting) { // Currently for testing purposes only. Breakpoint is set to setting.Count return Content(setting.Count.ToString()); } } 

查看( ~/Views/Settings/Index.cshtml ):

 @using (Html.BeginForm("Edit", "Settings", FormMethod.Post, new { @class = "form-horizontal", id = "editSettings" })) { foreach (Setting item in ViewBag.Settings) { @Html.Partial("_SingleSetting", item) }  } @section scripts {  } 

设置部分( ~/Views/Settings/_SingleSetting.cshtml ):

 @model Setting @{ var index = Guid.NewGuid().ToString(); ViewData.TemplateInfo.HtmlFieldPrefix = "[" + index + "]"; }  
@Html.EditorFor(model => model.Value)

注意如何在部分内部更改HtmlFieldPrefix,以便html帮助程序为输入字段生成正确的名称并遵守命名约定。


好吧,现在让我们剪切ViewCrap并正确处理事情(当然使用视图模型)。

我们一如既往地编写视图模型:

 public class MyViewModel { public IList Settings { get; set; } } 

然后我们调整控制器:

 public class SettingsController : Controller { public ActionResult Index() { var model = new MyViewModel(); // you will probably wanna call your database here to // retrieve those values, but for the purpose of my example that // should be fine model.Settings = Enumerable.Range(1, 5).Select(x => new Setting { SettingId = x, Name = "setting " + x, Value = "value " + x }).ToList(); return View(model); } [HttpPost] public ActionResult Edit(IList setting) { // Currently for testing purposes only. Breakpoint is set to setting.Count return Content(setting.Count.ToString()); } } 

查看( ~/Views/Settings/Index.cshtml ):

 @model MyViewModel @using (Html.BeginForm("Edit", "Settings", FormMethod.Post, new { @class = "form-horizontal", id = "editSettings" })) { @Html.EditorFor(x => x.Settings)  } @section scripts {  } 

设置模型的编辑器模板( ~/Views/Settings/EditorTemplates/Settings.cshtml ):

 @model Setting 
@Html.EditorFor(model => model.Value)

现在所有的工作按照惯例。 无需编写任何foreach循环。 索引视图中的@Html.EditorFor(x => x.Settings)调用分析视图模型的Settings属性,并检测它是某个其他模型的集合(在本例中为Setting )。 因此它将开始循环遍历此集合并搜索相应的编辑器模板( ~/Views/Settings/EditorTemplates/Setting.cshtml ),该模板将自动为此集合的每个元素呈现。 所以你甚至不需要在视图中编写任何循环。 除了简化代码之外,编辑器模板中的Html.EditorFor(x => x.Value)现在将为输入字段生成专有名称。