网络模型
public class User
{
public string Name { get; set; }
public LEmail LEmail { get; set; }
}
public class LEmail
{
public IList<CLabel> Labels;
public IList<CEmail> Emails;
}
public class CLabels
{
public IList<CLabel> Labels { get; set; }
}
public class CLabel
{
public string Name { get; set; }
}
public abstract class CEmail
{
public string SelectedLabel { get; set; }
public string Name { get; set; }
}
用虚拟数据填充它并将其作为User
对象发送到适当的视图,我在视图中有以下knockout定义:
@using (Html.BeginForm("MyAction", "MyController", FormMethod.Post, new { id = "MyEditor" }))
{
@Html.EditorFor(m => @Model.LEmail)
<p>
<input type="submit" value="Save" data-bind="enable: Emails().length > 0" />
<a href="/">Cancel</a>
</p>
<p data-bind="visible: saveFailed" class="error">A problem occurred saving the data.</p>
<div id="debug" style="clear: both">
<hr />
<h2>Debug:</h2>
<div data-bind="text: ko.toJSON(viewModel)"></div>
</div>
}
<script type="text/javascript">
$(function() {
ko.applyBindings(viewModel);
$("#profileEditorForm").validate({
submitHandler: function(form) {
if (viewModel.save())
window.location.href = "/";
return false;
}
});
});
var viewModel = {
Name: ko.observable("@Model.Name"),
Labels: ko.observableArray(@Html.Json(Model.LEmail.Labels) || []),
Emails: ko.observableArray(@Html.Json(Model.LEmail.Emails) || []),
addEmail: function() {
viewModel.Emails.push(@Html.Json(new CEmail()));
},
removeEmail: function(eml) {
viewModel.Emails.remove(eml);
},
saveFailed: ko.observable(false),
// Returns true if successful
save: function() {
var saveSuccess = false;
viewModel.saveFailed(false);
// Executed synchronously for simplicity
jQuery.ajax({
type: "POST",
url: "@Url.Action("MyAction", "MyController")",
data: ko.toJSON(viewModel),
dataType: "json",
contentType: "application/json",
success: function(returnedData) {
saveSuccess = returnedData.Success || false;
viewModel.saveFailed(!saveSuccess);
},
async: false
});
return saveSuccess;
}
};
</script>
最后是编辑器模板它实际上是用来处理可变长度列表的它看起来像这样:
@model MyDomain.ViewModels.LEmail
<table>
<tbody data-bind="template: { name: 'EmailsTemplate', foreach: Emails }" />
</table>
<button data-bind="click: addEmail">Add Email</button>
<script id="EmailsTemplate" type="text/html">
<tr>
<td>
@* PROBLEM IS HERE!! Labels won't show (they will it this code taken out of template) *@
<select data-bind="options: Labels"></select></td>
<td>
<input type="text" data-bind="value: Name, uniqueName: true" class="required" /></td>
<td>
<a href="#" data-bind="click: function() { viewModel.removeEmail(this); }">Delete</a></td>
</tr>
</script>
本质上是I
- 不能使其在组合框(或)的
EditorTemplate
中工作dropdownlist)。不管我怎么做,它都不会附着在标签上。如果我把它放到模板之外的其他地方——它会像预期的那样工作。 另外,根据选择填写"SelectedValue"在电子邮件-如何做到这一点。
一切选择后,(这必须是简单的)如何发布它在返回过程中不丢失值(这是一个超级嵌套模型)
提前非常感谢!
标签是在你的视图模型,而不是每个电子邮件。由于模板是在Knockout foreach绑定的上下文中呈现的,因此绑定上下文已更改为电子邮件。
我是这样写你的视图的:
@model FiveW.ViewModels.LabeledEmail
<table>
<tbody data-bind="foreach: Emails">
<tr>
<td>
<select data-bind="options: $root.Labels, value: SelectedLabel"></select>
</td>
<td>
<input type="text" data-bind="value: Name, uniqueName: true" class="required" />
</td>
<td>
<a href="#" data-bind="click: function() { viewModel.removeEmail(this); }">Delete</a>
</td>
</tr>
</tbody>
</table>
<button data-bind="click: addEmail">Add Labeled Email</button>
修复在$root中。标签:我们需要告诉Knockout使用$root(你的视图模型),因为标签实际上是在你的视图模型上,而不是在单个电子邮件上。
还要注意,我没有使用命名模板。这是可取的。除非你在视图的多个地方使用模板,否则你应该使用匿名的内联模板,就像我上面所做的那样。