如何更新列表<;模型>;在MVC4中使用jQuery

如何更新列表<;模型>;在MVC4中使用jQuery,jquery,collections,asp.net-mvc-4,Jquery,Collections,Asp.net Mvc 4,我目前正在尝试使用修改过的索引视图创建设置页面。目标是用户可以显示所有设置,可以在一个视图中更改所有设置,并使用一个按钮保存所有设置。应该使用Ajax更新设置 我当前的方法: 视图: 我正在使用ViewBag.Settings=\u db.Settings.ToList()设置ViewBag jQuery将数据解析为以下方法: [HttpPost] public ActionResult Edit(IList<Setting> setting) {

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

我当前的方法:

视图:

我正在使用
ViewBag.Settings=\u db.Settings.ToList()设置ViewBag

jQuery将数据解析为以下方法:

    [HttpPost]
    public ActionResult Edit(IList<Setting> setting)
    {
        Console.WriteLine(setting.Count);
        return Content(""); // Currently for testing purposes only. Breakpoint is set to setting.Count
    }
[HttpPost]
公共操作结果编辑(IList设置)
{
控制台写入线(设置计数);
返回内容(“”;//当前仅用于测试目的。断点设置为setting.Count
}
Count
抛出错误,因为设置为
null
。我很不确定如何解决这个问题

有人能给我一个提示吗

关于SO的主题已经介绍了在不使用Ajax的情况下更新集合。但我不明白重点


感谢您的帮助。

您正在使用一个
Ajax.BeginForm
并再次使用jQuery对表单进行Ajaxing。那没必要。但是,代码的真正问题是分部代码中输入字段的名称。您不遵守默认模型绑定器用于绑定到列表的选项

让我们举一个完整的例子(为了简单起见,消除所有干扰,如实体框架):

型号:

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> setting)
    {
        // Currently for testing purposes only. Breakpoint is set to setting.Count
        return Content(setting.Count.ToString()); 
    }
}
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> setting)
    {
        // Currently for testing purposes only. Breakpoint is set to setting.Count
        return Content(setting.Count.ToString()); 
    }
}
部分设置(
~/Views/Settings/\u SingleSetting.cshtml
):

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

@模型设置
@LabelFor(x=>x.Name)
@EditorFor(model=>model.Value)

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

非常感谢您的详细回答。这给了我一个关于EditorTemplates和List与视图结合使用的全新视图。
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> setting)
    {
        // Currently for testing purposes only. Breakpoint is set to setting.Count
        return Content(setting.Count.ToString()); 
    }
}
@using (Html.BeginForm("Edit", "Settings", FormMethod.Post, new { @class = "form-horizontal", id = "editSettings" }))
{
    foreach (Setting item in ViewBag.Settings) 
    {
        @Html.Partial("_SingleSetting", item)
    }
    <input type="submit" value="modify" />
}

@section scripts {
    <script type="text/javascript">
        $('#editSettings').submit(function () {
            if ($(this).valid()) {
                $.ajax({
                    url: this.action,
                    type: this.method,
                    data: $(this).serialize(),
                    success: function (result) {
                        alert(result);
                    }
                });
            }
            return false;
        });
    </script>
}
@model Setting
@{
    var index = Guid.NewGuid().ToString();
    ViewData.TemplateInfo.HtmlFieldPrefix = "[" + index + "]";
}

<input type="hidden" name="index" value="@index" />

<div class="control-group">
    <label class="control-label">@Html.LabelFor(x => x.Name)</label>
    <div class="controls">
        @Html.EditorFor(model => model.Value)
    </div>
</div>
public class MyViewModel
{
    public IList<Setting> 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> setting)
    {
        // Currently for testing purposes only. Breakpoint is set to setting.Count
        return Content(setting.Count.ToString()); 
    }
}
@model MyViewModel

@using (Html.BeginForm("Edit", "Settings", FormMethod.Post, new { @class = "form-horizontal", id = "editSettings" }))
{
    @Html.EditorFor(x => x.Settings)
    <input type="submit" value="modify" />
}

@section scripts {
    <script type="text/javascript">
        $('#editSettings').submit(function () {
            if ($(this).valid()) {
                $.ajax({
                    url: this.action,
                    type: this.method,
                    data: $(this).serialize(),
                    success: function (result) {
                        alert(result);
                    }
                });
            }
            return false;
        });
    </script>
}
@model Setting
<div class="control-group">
    <label class="control-label">@Html.LabelFor(x => x.Name)</label>
    <div class="controls">
        @Html.EditorFor(model => model.Value)
    </div>
</div>