传递一个集合EditorFor()时,它产生用于输入元素无效名称(when passing a co

2019-07-30 08:01发布

我有包括该书的平面信息,如标题,PublishYear和等加书作者的集合(复杂类型)的BookCreateModel:

public class BookCreateModel
{
    public string Title { get; set; }
    public int Year { get; set; }
    public IList<AuthorEntryModel> Authors { get; set; }
}

public class AuthorEntryModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

在CreateBook鉴于我已经使用EditorFor帮手:

@Html.EditorFor(m => m.Authors, "AuthorSelector")

EDIT1:

和AuthorSelector模板如下:

<div class="ptr_authors_wrapper">
    @for (int i = 0; i < Model.Count; i++)
    {
       <div class="ptr_author_line" data-line-index="@i">
        @Html.TextBoxFor(o => o[i].FirstName)
        @Html.TextBoxFor(o => o[i].LastName)
       </div>
    }
</div>
<script>
     ...
</script>

AuthorSelector模板包含需要知道每个渲染项目的索引加上一些javascript其处理孩子输入的交互,需要进行一次渲染(里面的一些包装标记AuthorSelector模板)/,从而摆脱的for循环或AuthorSelector模板是不可能的。

现在的问题是EditorFor行为有点怪,并产生这样的输入名字:

<input id="Authors__0__FirstName" name="Authors.[0].FirstName" type="text" value="" />
<input id="Authors__0__LastName" name="Authors.[0].LastName" type="text" value="" />

正如你所看到的,而不是像生成的名字Authors[0].FirstName它增加了一个额外的点,这使得默认的模型绑定无法解析发布的数据。

任何的想法 ?

谢谢 !

Answer 1:

我建议你坚持公约,如更换:

@Html.EditorFor(m => m.Authors, "AuthorSelector")

有:

@Html.EditorFor(m => m.Authors)

然后重命名你的~/Views/Shared/EditorTemplates/AuthorSelector.cshtml~/Views/Shared/EditorTemplates/AuthorEntryModel.cshtml并使它强类型的单一AuthorEntryModel模式,摆脱循环:

@model AuthorEntryModel
@Html.TextBoxFor(o => o.FirstName)
@Html.TextBoxFor(o => o.LastName)

ASP.NET MVC将自动生成的集合中的所有元素编辑模板,并产生适当的名称。


更新:

看到这里你更新后是我的回应:

在你的主观点:

<div class="ptr_authors_wrapper">
    @Html.EditorFor(m => m.Authors)
</div>

在编辑器模板:

@model AuthorEntryModel
<div class="ptr_author_line">
    @Html.TextBoxFor(o => o.FirstName)
    @Html.TextBoxFor(o => o.LastName)
</div>

你会发现其中是完全正常的模板没有剧本的。 脚本也没什么标记做。 他们去到单独的JavaScript文件。 在这个文件中,你可以使用jQuery做任何你需要与你的标记做。 它给你的方法,如.index()让您获得元素的索引匹配选择,这样你就不需要写任何循环和污染的东西像您的标记data-line-index的属性。



Answer 2:

我有点迟到了,但希望这可以帮助别人。

挖下来System.Web.Mvc.Html.DefaultEditorTemplates.CollectionTemplate(HtmlHelper html, TemplateHelpers.TemplateHelperDelegate templateHelper)该框架的默认模板由临时设置处理该HtmlFieldPrefix为空字符串,并明确地传递前缀和索引调用EditorFor()

<div class="ptr_authors_wrapper">
@{
    var prefix = ViewData.TemplateInfo.HtmlFieldPrefix;

    ViewData.TemplateInfo.HtmlFieldPrefix = String.Empty;

    for (int i = 0; i < Model.Count; i++)
    {
        <div class="ptr_author_line" data-line-index="@i">
            @* You can also use null instead of "TextBox" to let the framework resolve which editor to use. *@
            @Html.EditorFor(o => o[i].FirstName, "TextBox", String.Format("{0}[{1}].FirstName", prefix, i))
            @Html.EditorFor(o => o[i].LastName, "TextBox", String.Format("{0}[{1}].LastName", prefix, i))
        </div>
    }

    ViewData.TemplateInfo.HtmlFieldPrefix = prefix;
}
</div>
<script>
     ...
</script>

我发现这个特别有用的框架正在写名称为[0].Children.[0].ChildProperty由于对儿童收集命名模板。 在我的情况下,解决办法是拨打:

@Html.EditorFor(m => m[i], null, String.Format("{0}[{1}]", prefix, i))

而不是简单地调用:

@Html.EditorFor(m => m[i])


Answer 3:

不知道它是否仍然是相关的,但这个博客涵盖了解决问题的方法: http://btburnett.com/2011/03/correcting-mvc-3-editorfor-template-field-names-when-using-collections html的

- >积分去itsmatt寻找它:)雅各布



Answer 4:

这里是你可以用这会使局部视图,并使用正确的HTML字段前缀的扩展方法:

扩展方法

    /// <summary>
    /// Helper method that renders the specified partial view as a HTML-encoded string using the specified
    /// collection as the model, with the intention that the partial view will use an editor template on the items
    /// in the collection.
    /// </summary>
    /// <typeparam name="TModel">the model type</typeparam>
    /// <typeparam name="TProperty">the property type</typeparam>
    /// <param name="htmlHelper">the <see cref="HtmlHelper"/> instance</param>
    /// <param name="partialViewName">the name of the partial view to render</param>
    /// <param name="collectionExpression">the model collection property expression</param>
    /// <returns>the HTML-encoded string</returns>
    public static MvcHtmlString PartialContainingEditorForCollection<TModel, TProperty>
        (this HtmlHelper<TModel> htmlHelper, string partialViewName,
         Expression<Func<TModel, TProperty>> collectionExpression)
        where TProperty : IEnumerable
    {
        var viewData = htmlHelper.ViewContext.ViewData;
        var model = (TModel) viewData.Model;
        var collection = collectionExpression.Compile().Invoke(model);

        var htmlFieldPrefix = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(
            ExpressionHelper.GetExpressionText(collectionExpression));

        return htmlHelper.Partial(partialViewName, collection,
                                  new ViewDataDictionary
                                      {
                                          TemplateInfo = new TemplateInfo {HtmlFieldPrefix = htmlFieldPrefix}
                                      });
    }

用法示例

@Html.PartialContainingEditorForCollection("_TableWithSummary", m => Model.FormModel.ItemsToOrder)


Answer 5:

我没有找到任何解决这个错误还,但作为一种解决方法我改变了我UpdateModel通过使用自定义包装类,而不是直接使用集合:

public class BookCreateModel
{
    public string Title { get; set; }
    public int Year { get; set; }
    public BookAuthorsList Authors { get; set; }
}

public class BookAuthorsList
{
    public IList<AuthorEntryModel> AuthorsList { get; set; }
}

public class AuthorEntryModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

而由此产生的投入不会做出了命名问题:)

<input  id="Authors_AuthorsList_0__FirstName" name="Authors.AuthorsList[0].FirstName" type="text"/>
<input  id="Authors_AuthorsList_0__LastName" name="Authors.AuthorsList[0].LastName" type="text"/>


Answer 6:

我偶然发现了这个,当我试图找到几乎相同的问题的解决方案。 我的解决方法是踢罐头的道路,即。 使包装模型的收集和使用,在编辑模板。 在提供的情况下,这将是:

public class BookCreateModel
{
    public string Title { get; set; }
    public int Year { get; set; }
    public BookAuthorsModel Authors { get; set; }
}

public class BookAuthorsModel
{
    IList<AuthorEntryModel> Items { get; set; }
}

然后你的编辑模板,重新命名为“BookAuthorsModel.cshtml”,使之像这样:

@model BookAuthorsModel
<div class="ptr_authors_wrapper">
    @for (int i = 0; i < Model.Items.Count; i++)
    {
       <div class="ptr_author_line" data-line-index="@i">
        @Html.TextBoxFor(o => Items.o[i].FirstName)
        @Html.TextBoxFor(o => Items.o[i].LastName)
       </div>
    }
</div>
<script>
     ...
</script>

而当你要使用它,只需拨打:

@Html.EditorFor(m => m.Authors)

然后,它应该产生像这样输入字段:

<input id="Authors_Items_0__FirstName" name="Authors.Items[0].FirstName" type="text" value="" />
<input id="Authors_Items_0__LastName" name="Authors.Items[0].LastName" type="text" value="" />

在我来说,我也适当改变Automapper映射设置控制器代码。 这不是然而,一些更复杂的场景可用,因此可能只是一种变通方法。



文章来源: when passing a collection to EditorFor(), it generates invalid names for input elements