如何在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)
现在将为输入字段生成专有名称。