为了在客户端使用在服务器端编写的视图模型,我使用了 knockoutjs 映射插件。但在我看来,我并不想写任何 js 代码。出于这个原因,因此我无权访问Model
,我现在通过 ajax 调用获取模型,下面代码中的属性中没有值。这段代码写在一个外部的 js 文件中:
var Person = function () {
var self = this;
self.SetupKOBindings = function (flagkey) {
var source = null;
if (flagkey.val() === "True") {
this.GetViewModelFromServer = function () {
$.ajax(
{
url: "/Person/LoadData",
type: "GET",
async: false
}).
success(function (data) {
if (data !== null && data !== undefined) {
source = data;
flagkey.val("false");
}
});
}();
return ko.mapping.fromJS(source);
}
return null;
};
self.ViewModel = function (flagkey) {
this.model = self.SetupKOBindings(flagkey);
this.model.FullName = ko.computed(function () {
return this.model.FirstName() + " " + this.model.LastName();
});
this.model.ShouldShowFullName = ko.computed(function () {
return (this.model.FirstName() === null || this.model.LastName() === null) ? false : true;
});
this.model.Save = function () {
if ($(form).valid()) {
$.ajax(
{
url: "/Person/Index",
type: "POST",
contentType: "application/json",
data: ko.mapping.toJSON(model),
async: true
}).
success(function (data) {
ko.mapping.fromJS(model, data);
});
}
}
return this.model;
};
self.ApplyKOBindings = function (vm) {
ko.applyBindings(vm);
};
return this;
};
$(function () {
var PersonPage = Person();
var viewModel = PersonPage.ViewModel($('#GetViewModelFromServer'));
if (viewModel !== null) PersonPage.ApplyKOBindings(viewModel);
});
我遇到这种方法的问题是每次我执行发布操作时,当页面加载时,会触发相同的 ajax 请求以从服务器获取视图模型,并且运行相同的代码,然后将表单与空的 vm 属性绑定。
为了避免这种情况,我使用隐藏控件的值作为是否将服务器端视图模型转换为 js 对象的标志。所以,在第一次调用时,我将 flag 的值设置为 false。
现在为了获得使用数据注释提到的验证消息,我将表单设置为部分视图,并使用 ajax 调用将内容替换为带有 id 作为示例的 div。使用不显眼的验证和服务器端验证的客户端验证效果非常好,淘汰绑定也是如此。
控制器代码:
[HttpPost]
public ActionResult Index(PersonViewModel viewModel)
{
if (viewModel.Age < 10)
{
ModelState.AddModelError("Age", "bal bla bla");
}
if (ModelState.IsValid)
{
return PartialView("_Form", viewModel);
}
else
{
viewModel.GetViewModelFromServer = false;
return PartialView("_Form", viewModel);
}
}
索引视图:
<div id="sample">
@Html.Partial("_Form")
</div>
局部视图:
@model MVCKOPractise.Models.PersonViewModel
<fieldset>
<legend>PeopleViewModel</legend>
@using (Ajax.BeginForm("Index", "Person", new AjaxOptions() { InsertionMode = InsertionMode.Replace, HttpMethod = "POST", UpdateTargetId = "sample" }))
{
<div>
First Name:
@Html.TextBoxFor(model => model.FirstName, new { data_bind = "value: FirstName,valueUpdate:['afterkeydown','propertychange','input']" })<br />
@Html.ValidationMessageFor(model => model.FirstName)
</div>
<div>
Last Name:
@Html.TextBoxFor(model => model.LastName, new { data_bind = "value: LastName,valueUpdate:['afterkeydown','propertychange','input']" })<br />
@Html.ValidationMessageFor(model => model.LastName)
</div>
<div data-bind="visible: ShouldShowFullName">
Full Name:
<div data-bind="text: FullName"></div>
</div>
<div>
Address:
@Html.TextBoxFor(model => model.Address, new { data_bind = "value: Address" })<br />
@Html.ValidationMessageFor(model => model.Address)
</div>
<div>
Age:
@Html.TextBoxFor(model => model.Age, new { data_bind = "value: Age" })<br />
@Html.ValidationMessage("Age")
</div>
@Html.HiddenFor(model => model.GetViewModelFromServer)
<input type="submit" value="Save" />
}
</fieldset>
虽然上面的小样本对我有用,但我想知道这是继续进行的好方法
- 不要在视图中编写 js 代码并使用 ajax 调用在客户端创建视图模型的副本,使用 data- 属性访问 javascript 中的任何服务器端内容,就像我回答的那样。
- 使用在服务器端使用数据注释为视图编写的相同验证。我知道有一个可用的淘汰赛验证和 jquery-validation 插件。但是由于 mvc 数据注释将验证转换为数据属性,然后由 jquery 读取。