Quantcast
Channel: 黑暗執行緒
Viewing all articles
Browse latest Browse all 2311

KO範例27 - ViewModel物件的擴充

$
0
0

為了確保Server端及Client端的ViewModel一致,在專案中我使用T4自動產生對應C# Class及JavaScript function,如此可確保ASP.NET端拋出的ViewModel與Client端的ViewModel完全一致,雖然這點Knockout Mapping Plug-In也辦得到,但自己產生的JavaScript ViewModel還可以加上JavaScript Documentation註解,配合Visual Studio強大的JS Intellisense功能,爽度是無法相比滴~

但有個小問題: 除了自動產生的屬性外,常會因開發需要還得額外加入UI控制用途的ko.observable或ko.computed,這部分在開發過程常會機動修改調整,不適合綁進自動產生程序,事後外加是較好抉擇。一開始我想得天真,以為用vm.prototype.anotherProp就可輕鬆搞定,後來卻發現這招處理ko.observable可行,遇到ko.computed時會因無法存取當下Instance而陷入困境。在ko.computed函數中,我們無法透過this取得當時物件,而宣告prototype時物件個體尚不存在,故也不可能當成ko.computed的第二個參數傳入,結果空有ko.computed卻無法依賴其他屬性進行運算。

<!DOCTYPEhtml>
<html>
<head>
<scriptsrc="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js">
</script>
<meta charset=utf-8 />
<title>KO範例27 - 擴充ViewModel(失敗)</title>
</head>
<body>
<input data-bind="value: foo" />
<div>fooPlusX = <span data-bind="text: fooPlusX"></span></div>
<script>
//透過CodeGen自動產生的ViewModel
function VMBoo() {
var self = this;
      self.foo = ko.observable(1);
    }
//事後想為ViewModel多加一個fooPlusX屬性,
//天真地想透過prototype加掛ko.computed直接搞定
    VMBoo.prototype.fooPlusX = ko.computed(function() {
try {
//問題來了,在ko.computed中無從存取當時的instance
returnthis.foo() + "X";
      }
catch (err) {
return err.message;
      }
    }); //instnace在此時當不存在,也無法當成參數傳給ko.computed
var vm = new VMBoo();
    ko.applyBindings(vm);
</script>
</body>
</html>

在以上的失敗範例中,只會得到fooPlusX = Object [object global] has no method 'foo'的結果。線上展示

最後我找到一個解法,先在ViewModel的建構函式中埋下伏筆:
if (this.init) this.init(self);

而這個init函式可以透過vm.prototype.init = function(self) { … }加以定義,如此在init便能取得self(當時的物件個體)為所欲為,跟在建構式的寫法一致。線上展示

<!DOCTYPEhtml>
<html>
<head>
<scriptsrc="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js">
</script>
<meta charset=utf-8 />
<title>KO範例27 - 擴充ViewModel(成功)</title>
</head>
<body>
<input data-bind="value: foo" />
<div>fooPlusX = <span data-bind="text: fooPlusX"></span></div>
<script>
//透過CodeGen自動產生的ViewModel
function VMBoo() {
var self = this;
      self.foo = ko.observable(1);
//CodeGen時額外呼叫透過prototype定義的init
if (this.init) this.init(self);
    }
//宣告額外的init函式
    VMBoo.prototype.init = function(self) {
      self.fooPlusX = ko.computed(function() {
return self.foo() + "X";
      });
    };
var vm = new VMBoo();
    ko.applyBindings(vm);
</script>
</body>
</html>

就醬,又排除掉偉大航道上的一個小障礙囉~

[KO系列]

http://www.darkthread.net/kolab/labs/default.aspx?m=post

Viewing all articles
Browse latest Browse all 2311

Trending Articles