題目比較拗口,但是這篇文章確實直說這一點。
knockout.js是一個JS庫,它的官網是http://knockoutjs.com/
這篇文章的重點是knockout在工作的一個功能中的應用。最終效果圖如下:
點擊Add Other Source UI添加一個空行
現有行可以直接修改
點擊delete UI刪除當前行
點擊保存時數據才會錄入到服務器
Html代碼如下
<div class="row">
<span class="label">Information from other sources:</span>
<table class="inline-dataTable">
<thead>
<tr>
<td>
Test
</td>
<td>
Date
</td>
<td>
Scores
</td>
<td>
Action
</td>
</tr>
</thead>
<tbody data-bind="foreach: OtherSources">
<tr>
<td>
<input required="required" class="required" data-bind="value: Test, uniqueName: true, uniqueId: Test" /><span
class="field-validation-valid" data-bind="valmsg: true" data-valmsg-replace="true" />
</td>
<td>
<input id="Date" class="Date required noFutureDate" required="required" data-bind="value: Date, uniqueName: true, dateName: true, uniqueId: Date" /><span
class="field-validation-valid" data-bind="valmsg: true" data-valmsg-replace="true" />
</td>
<td>
<input required="required" class="required number" data-bind="value: Scores, uniqueName: true, uniqueId: Scores" /><span
class="field-validation-valid" data-bind="valmsg: true" data-valmsg-replace="true" />
</td>
<td>
<a href="#" data-bind="click: function(){ viewModel.removeOtherSource($data) } ">delete</a>
</td>
</tr>
</tbody>
</table>
<div class="add-button">
<a href="#" id="ButtonAddOtherSource" data-bind="click: addOtherSource">Add Other Source</a>
</div>
</div>
Js代碼如下:
$(document).ready(function () { // NOTE: KnockoutJS unique id generator (http://stackoverflow.com/questions/9233176/unique-ids-in-knockout-js-templates) ko.bindingHandlers.uniqueId = { init: function (element, valueAccessor) { var value = valueAccessor(); value.id = value.id || ko.bindingHandlers.uniqueId.prefix + (++ko.bindingHandlers.uniqueId.counter); element.id = value.id; }, counter: 0, prefix: "unique" }; // 這是為每個element生成不同ID ko.bindingHandlers['uniqueName'] = { 'currentIndex': 0, 'init': function (element, valueAccessor) { if (valueAccessor()) { element.name = "ko_unique_" + (++ko.bindingHandlers['uniqueName'].currentIndex); // Workaround IE 6/7 issue // - https://github.com/SteveSanderson/knockout/issues/197 // - http://www.matts411.com/post/setting_the_name_attribute_in_ie_dom/ if (ko.utils.isIe6 || ko.utils.isIe7) element.mergeAttributes(document.createElement("<input name='" + element.name + "'/>"), false); } } }; // 這是為每個element生成不同Name ko.bindingHandlers['dateName'] = { init: function (element, valueAccessor) { if (valueAccessor()) { $('#' + element.id).kendoDatePicker({ format: "MM/dd/yyyy" }); } } }; //這是為包含dateName的元素添加了一個DatePicker
ko.bindingHandlers.valmsg = { init: function (element) { element.setAttribute("data-valmsg-for", "ko_unique_" + ko.bindingHandlers.uniqueName.currentIndex); } }; //這是利用element的name顯示驗證信息
ko.applyBindings(viewModel); }); var OtherSource = function(data) { var self = this; self.Test = ko.observable(data.Test); self.Date = ko.observable(data.Date); self.Scores = ko.observable(data.Scores); }; @{ var otherSources = Json.Encode(Model..........); } var jsonOtherSources = @Html.Raw(otherSources); var viewModel = { OtherSources: ko.observableArray(ko.utils.arrayMap(jsonOtherSources, function(otherSource) { return new OtherSource(otherSource); })), addOtherSource: function() { this.OtherSources.push({ Test: ko.observable(""), Date: ko.observable(""), Scores: ko.observable("") }); }, removeOtherSource: function(otherSource) { this.OtherSources.remove(otherSource); }, };
上述代碼的data-bind,addOtherSource,removeOtherSource等在官網都有詳細的說明。
那我就只說一下在項目中出現的代碼。
uniqueId ,uniqueName是增加的一些屬性,用來做驗證。最終生成的Html如下:
這樣就生成了MVC中 ValidationMessageFor類似的驗證代碼,幫助我們在在頁面層進行驗證
當看到uniqueId ,uniqueName的綁定和生成方式之后,覺得這代碼N。
這也是我要這篇文章的最初原因。
最后再來一點與本題無關,但是保存時候的需要用到的代碼吧
if ($("form#editForm").valid()) {
var data = $.deparam($("form#editForm").serialize());
data["OtherSources"] = ko.mapping.toJSON(viewModel.OtherSources);
$.post('@Url.Action("actionName", "ctlName", new {area = "***"})', data, function(result) {
HandleAjaxResult(result);
});
}
var otherSources = Request.Form["OtherSources"];
if (!string.IsNullOrEmpty(otherSources))
{
var otherSourceDtos = JsonConvert.DeserializeObject<List<OtherSourceDto>>(otherSources);
//save data to db…….
}