这是我面临的问题,不知道如何处理它:
我在ASP.NET MVC 4中创建了模型,控制器和视图。有一次我不得不创建动态列表,所以我选择了KnockoutJS,这很容易解决这个问题。到现在为止还挺好。 然后我意识到我使用Fluent Validation在我的MVC模型上定义的验证在淘汰视图中不再起作用。
我搜索了SO并找到了一些可行的解决方案:
我倾向于使用后者,原因有几个。主要是因为它给了我机会不介绍(学习,测试,本地化,花时间)另一个图书馆。
我对MVC非常熟悉并喜欢它支持本地化的方式,可以完全控制消息,标签等。我也喜欢Fluent验证,不想用其他人替换它(更静态,更难以本地化,更多根据自己的喜好不太灵活)
当数据绑定必须成为data_bind等时,我找到了一些关于敲除razor转换的例子。
我无法找到用and in表达foreach循环的方法。
MVC视图模型
public class ContactEmail
{
public string SelectedLabel { get; set; }
public string Name { get; set; }
}
public class User
{
public IList<ContactEmail> Emails { get; set; }
}
ViewBag.EmailLabels = new string[] { "label1", "label2", ... };
淘汰模型
var viewModel = {
EmailLabels: ko.observableArray(@Html.Json(ViewBag.EmailLabels as string[]) || []),
Emails: ko.observableArray(@Html.Json(@Model.Emails) || []),
}
淘汰视图(我想改造)
<table>
<tbody data-bind="foreach: Emails">
<tr>
<td>
@* How to make razor below work instead of knockout syntax below it? *@
@*Html.DropDownListFor(m => ????, new { data_bind="options: $root.EmailLabels, value: SelectedLabel, optionsCaption: 'Choose...'" } )
<select data-bind="options: $root.EmailLabels, value: SelectedLabel, optionsCaption: 'Choose...'"></select></td>
<td>
@* How to make razor below work as well instead of knockout syntax below ?!?!? *@
@Html.TextBoxFor(m => ????, new { data_bind="value: Name, uniqueName: true" } )
<input type="text" data-bind="value: Name, uniqueName: true" class="required email" />
</td>
<td>
<a href="#" data-bind="click: function() { viewModel.removeEmail(this); }">Delete</a>
</td>
</tr>
</tbody>
</table>
我看了MVC Controls toolkit一个人无情地宣传的内容将解决我所有的验证和本地化以及一切。我发现它无法使用,非常专有并且非常难以理解。它就像购买核武杀死一只鸟。
所以,请那些有MVC与淘汰赛结合经验的人,请加强并分享您的经验。
任何帮助将不胜感激&amp;非常感谢你。
答案 0 :(得分:0)
编辑:更新以包含确定的Knockout Bindings
<强> index.cshtml 强>
@model Stackoverflow5.Models.User
<form>
<table>
<tbody>
@{
var tempdropdownlist = new List<SelectListItem>();
}
@for (var i = 0; i < @Model.Emails.Count; i++)
{
<tr>
<td>
@Html.DropDownListFor(m => m.Emails[i], tempdropdownlist,
new { data_bind = String.Format("options: $root.EmailLabels, value: Emails()[{0}].SelectedLabel, optionsCaption: 'Choose...'", i)})
</td>
<td>
@Html.TextBoxFor(m => m.Emails[i].Name,
new { data_bind = String.Format("value: Emails()[{0}].Name(), uniqueName: true", i) })
</td>
</tr>
}
</tbody>
</table>
<button type="submit">Test</button>
</form>
**模型(验证工作)**
public class ContactEmail
{
public string SelectedLabel { get; set; }
[Required]
[StringLength(20, MinimumLength = 2)]
public string Name { get; set; }
}
public class User
{
public User()
{
Emails = new List<ContactEmail>();
EmailLabels = new List<string> {"Important", "Spam", "Family"};
}
public List<ContactEmail> Emails { get; set; }
public List<string> EmailLabels { get; set; }
}
答案 1 :(得分:0)
我认为这有点像黑客,但它确实有效。
控制器将返回User.Emails属性内的电子邮件集合,其中包含需要呈现的列表。 Razor View产生的是一个只有一行的表格的HTML,并且基于电子邮件IEnumerable的第一个元素进行验证(必须检查此为null或者可能导致异常)。
当ko.applyBindings()出现在客户端时,tbody标签上的foreach将生成所有行,并且由于ko ViewModel与整个集合一起初始化为映射的JsonString,因此整个列表将呈现。 removeEmail和addEmail方法也可以正常工作(我刚刚测试了removeEmail选项,它工作= D)
@using Newtonsoft.Json
@model Stackoverflow5.Models.User
<table>
@{var tempdropdownlist = new List<SelectListItem>();}
<tbody data-bind="foreach: Emails">
<tr>
<td>
@Html.DropDownListFor(m => m.Emails.First().SelectedLabel, tempdropdownlist,
new { data_bind="options: $root.EmailLabels, value: SelectedLabel, optionsCaption: 'Choose...'" })
<td>
@Html.TextBoxFor(m => m.Emails.First().Name, new { data_bind="value: Name, uniqueName: true" } )
</td>
<td>
<a href="#" data-bind="click: function () { viewModel.removeEmail(this); }">Delete</a>
</td>
</tr>
</tbody>
</table>
@section scripts
{
<script src="~/Scripts/knockout-2.2.1.js"></script>
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<script>
//Model definition
var viewModel,
ModelDefinition = function (data) {
//Object definition
var self = this;
//Mapping from ajax request
ko.mapping.fromJS(data, {}, self);
self.removeEmail = function(row) {
self.Emails.remove(row);
};
self.addEmail = function() {
//Method for adding new rows here
};
};
$(function() {
viewModel = new ModelDefinition(@Html.Raw(JsonConvert.SerializeObject(Model)));
ko.applyBindings(viewModel);
});
</script>
}