在ASP.NET MVC4模型绑定器中将ViewModels与动态嵌套集合绑定

时间:2013-05-29 20:49:40

标签: c# jquery asp.net-mvc-4 dynamic model-binding

我正在构建一个简单的Web应用程序,用户可以对管理员设置的主题进行投票。每个主题,可以有两个或更多选项,例如是或否样式投票主题,将有两个选项,其中作为“什么是肯辛顿最好的餐厅?”的投票主题。可以有很多选择。

这是我当前的ViewModel:

public class NewTopicVM
{
    [Required]
    [Display(Name = "Topic Title")]
    public string TopicTitle { get; set; }

    [Required]
    [Display(Name = "Topic Description")]
    public string TopicDescription { get; set; }

    [Display(Name = "Topic Image")]
    public byte[] TopicImage { get; set; }
    public List<NewOptionVM> TopicOptions { get; set; }
}

public class NewOptionVM
{
    public string OptTitle { get; set; }
    public string OptDescription { get; set; }
}

请注意NewOptionVM中的NewTopicVM列表。感谢Iko的回答,我已经设法绑定非动态生成的输入,但是我动态生成的输入不会因某种原因而受到约束!

以下是创建Option输入字段的jQuery代码:

var index = 1;

function generateOptMarkup() {
    var container = $('<div />');

    var optionInputsBlock = $('<div />');
    optionInputsBlock.addClass('optionInputsBlock');

    var inputTitleBlock = $('<div />');
    inputTitleBlock.addClass('inputBlock');

    var inputDescBlock = $('<div />');
    inputDescBlock.addClass('inputBlock');

    var optTitleLbl = $('<label />');
    optTitleLbl.attr('for', 'TopicOptions_' + ++index + '__OptTitle');
    optTitleLbl.text('Option Title');

    var optDescLbl = $('<label />');
    optDescLbl.attr('for', 'TopicOptions_' + index + '__OptDescription');
    optDescLbl.text('Option Description');

    var optTitleInpt = $('<input type="text" />');
    optTitleInpt.addClass('text-box single-line');
    optTitleInpt.attr('name', 'TopicOptions_' + index + '__OptTitle');
    optTitleInpt.attr('id', 'TopicOptions_' + index + '__OptTitle');
    optTitleInpt.attr('data-val-required', 'The Option Title field is required.');
    optTitleInpt.attr('data-val', 'true');

    var optDescInpt = $('<input type="text" />');
    optDescInpt.addClass('text-box single-line');
    optDescInpt.attr('name', 'TopicOptions_' + index + '__OptDescription');
    optDescInpt.attr('id', 'TopicOptions_' + index + '__OptDescription');
    optDescInpt.attr('data-val-required', 'The Option Description field is required.');
    optDescInpt.attr('data-val', 'true');

    inputTitleBlock.append(optTitleLbl).append(optTitleInpt);
    inputDescBlock.append(optDescLbl).append(optDescInpt);

    optionInputsBlock.append(inputTitleBlock).append(inputDescBlock);

    container.append(optionInputsBlock);

    return container.html();
}


$('div.buttons > a').click(function () {
    $('div.topicOptionsBlock').append(generateOptMarkup());
});

我从Index = 1开始,因为我已经显示了2个选项。这是一个截图:

enter image description here

前两个框被绑定得很好,但是点击[添加选项]按钮后动态添加的第三个框没有!

我做错了什么?我确保索引是正确的,但它不起作用:(

1 个答案:

答案 0 :(得分:2)

使用for循环遍历列表并使用索引和编辑器。

// other fields as usual

For(int i = 0; i < Model.TopicOptions.Count; i++)
{
    @Html.EditorFor(m => m.TopicOptions[i].OptTitle)
    @Html.EditorFor(m => m.TopicOptions[i].OptDescription)
}

MVC默认绑定现在会捕获它们。 如果你检查HTML MVC有一些格式来绑定它们,所以它就像TopicOptions__0_OptTitle。

在动作上放置一个断点,模型应该完全绑定,你不需要手动做任何事情。

编辑。 您可以将for循环的内部(2个editorFors)放在PartialView中,然后在调用它时通过ViewData传递索引。

for(...)
    @Html.Partial("_NewOption", new ViewDataDictionary { { "index", i } })

现在,如果您动态添加新项目,则可以对操作进行ajax调用,以返回列表,其中最后一项是新对象。该操作应返回索引,然后绑定将正常,因为名称和ID将自动生成。 (您也可以将所有内容发送到服务器进行删除)

这取决于您是想在javascript中手动处理id / name字段,还是从服务器自动处理。