サーバー側で作成したビューモデルをクライアント側で利用するために、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 オブジェクトに変換するかどうかのフラグとして使用しています。そのため、最初の呼び出しでフラグの値を false に設定しました。
データ注釈を使用して言及された検証メッセージを取得するために、フォームを部分ビューとして作成し、ajax 呼び出しを使用してコンテンツを div のサンプルとして id に置き換えます。unobtrusive-validation とサーバー側の検証を使用したクライアント側の検証は非常にうまく機能し、ノックアウト バインディングも機能します。
コントローラーコード:
[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 data-annotations は検証を data- 属性に変換し、それが jquery によって読み取られます。