【问题标题】:MVC EditorFor Remove Indexed NameMVC EditorFor 删除索引名称
【发布时间】:2014-03-05 15:36:24
【问题描述】:

我的模型是另一个模型的列表,例如 ModelList : ModelSingle 在我的剃刀视图中,我正在使用

@model somenamespace.ModelList
@Html.EditorForModel()

这会遍历每个 ModelSingle 并返回一个对 ModelSingle 进行强类型化的 EditorTemplate。

@model somenamespace.ModelSingle
@using(Html.BeginForm("Action", "Controller", FormMethod.Post, new { id = "formname" + Model.ID}))
{
    @Html.AntiForgeryToken()
    @Html.EditorFor(p => p.SomeField)
    @Html.EditorFor(p => p.AnotherField)
}

这些模板中的每一个都包含一个可用于编辑单个模型的表单。这些是单独发布的,我的控制器方法期望

public ActionResult(ModelSingle model)

我遇到的问题是模型没有正确绑定。使用这样的模型

public class ModelSingle()
{
    public string SomeField { get; set; }
    public string AnotherField { get; set; }
}

EditorTemplate 被告知它是列表的一部分,所以我得到了

<Form>
    <input name="[0].SomeField"/>
    <input name="[0].AnotherField"/>
    <input type="submit" value="Update"/>
</Form>

我不能简单地绑定到 ModelList,因为它没有命名 ModelList[0].SomeField,即使它是我认为除了第一个项目之外其他任何东西都不起作用。

有没有办法让 EditorTemplate 忽略它的模型是列表的一部分这一事实,或者强制 DropDownListFor、EditorFor 等......只使用字段名称而不添加 [i]。

我知道我可以强制执行 Name="SomeField" 更改,但我希望有一个解决方案能够反映 Model 类本身所做的任何更改。

编辑 - 按要求添加了正在使用的 View 和 EditorTemplate 的简化示例。

【问题讨论】:

  • 你能在视图和模板的顶部显示@model 标签吗?

标签: c# asp.net-mvc asp.net-mvc-4 razor


【解决方案1】:

此问题与您的页面模型(列表)生成的输入名称与您的操作预期的模型(列表中的单个项目)不匹配有关。

渲染列表时,默认行为是像您向我们展示的那样渲染索引名称([#] 符号)。由于您希望能够发布列表中的任意项目,因此您不会提前知道使用了什么索引。当模型绑定器查看单个对象的请求时,它不会尝试使用索引表示法。

我不知道从用户的角度来看您的要求是什么 - 例如。无论是否需要刷新页面,但实现此目的的一种方法是为要发布的特定项目提供一个 jQuery 帖子:

// pass jquery form object in
var postItem = function($form) {
    var postBody = {
        SomeField: $form.find('input selector')    // get your input value for this form
        AnotherField: '' // another input select for this item
    }

    $.ajax({
        url:'<your action url>', 
        type: 'POST',
        contentType:"application/json; charset=utf-8",
        data: JSON.stringify(postBody),
        dataType: 'json',
        success: function(response) {
            // do something with returned markup/data
        }
    });
}

您正在使用 json 对象手动序列化模型的单个实例并将其发布。您从操作返回的内容取决于您:用于刷新特定项目的新标记、用于简单状态的 json 数据等。

或者,您可以考虑手动循环遍历集合中的项目,并使用 Html.RenderPartial/Html.Partial 使用 View 模板呈现每个项目。这将缩短每个项目的名称生成,并将生成名称,就好像它是 ModelSingle 的单个实例一样。

最后,一个快速(但有点难看)的解决方法是让您的操作方法获取 ModelSingle 对象的列表。我不建议这样做。

编辑:我错过了将 json 发布到 mvc 操作的一些重要方面

Edit2:在您对硬编码名称发表评论后,这样的事情可能会有所帮助:

    var inputs = $form.find('all input selector');
    var jsonString = '{';
    $.each(inputs, function(index, element) {
        var parsedName = element.attr('name').chopOffTrailingFieldName();
        jsonString += parsedName + ":'" + element.val() + "',";
    });
    jsonString += '}';

【讨论】:

  • 谢谢马夫。我实际上是通过 Jquery Ajax 发布这些项目(尽管目前对整个表单进行了简单的序列化)。当更新单个项目时,控制器中的操作方法返回带有新值(或任何错误)的 EditorTemplate。然后用新的 EditorTemplate 替换当前的 EditorTemplate,并且 Jquery 重新绑定以拦截提交。我知道 Parent 被强输入到一个列表,但 EditorTemplate 被强输入到单个项目,就像 post 方法一样,所以我不明白为什么它坚持使用索引名称。
  • 简单的序列化是问题所在:它只是使用了 mvc 创建的名称。区别在于手动序列化将为您提供绑定单个 ModelSingle 对象所需的名称。
  • 关于索引名称:长话短说,父页面正在呈现一个列表,因此它正在为每个项目创建索引。由于您使用的是 Html.EditorFor* 方法,因此编辑器模板在渲染时透明地从父视图接收索引前缀。通过使用第二个选项(渲染部分),父视图的上下文被破坏,因此 EditorTemplate 不再具有用于构建索引名称的前缀。
  • 我希望避免硬编码名称路线,以防模型中的字段名称由于某种原因发生更改。如果需要,我可以从 EditorTemplate 中强制命名。如果可能的话,我宁愿找到问题的原因,也不愿破解解决方法。如果没有,则必须手动输入名称(或根据您的示例添加类选择器)。
  • Bingo - 您对 EditorFor 与部分破坏索引的解释是正确的。将 Html.EditorForModel() 更改为 foreach(var singleModel in Model){ Html.Partial(singleModel.GetType().Name, singleModel) } 让一切都像魅力一样工作。谢谢您的帮助。非常感谢。
猜你喜欢
  • 2015-06-28
  • 2011-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多