2013-01-22 14 views
0

我很確定我錯過了上下文的某些內容,但我無法弄清楚是什麼。

我有以下視圖模型:

var ViewModel = function(){ 
    var self = this; 
    self.person = ko.observable(); 
    self.isPerson = ko.observable(); 

    self.person.subscribe(function(value){ 
     self.isPerson('firstName' in value); 
    }); 
}; 

var vm = new ViewModel(); 
var personA = { }; 
var personB = { firstName: ko.observable("hello") }; 

vm.person(personA); 
ko.applyBindings(vm); 
setTimeout(function(){ vm.person(personB); }, 1000); 

及以下觀點:

<span data-bind="with: person"> 
    <!-- ko if: $root.isPerson --> 
     <span data-bind="text: firstName"></span> 
    <!-- /ko -->  
</span> 

JSFiddle

一旦超時執行,我期望在中顯示的的firstName但是,我收到以下錯誤:

firstName is not defined; 

如果我從viewModel中的personB開始,它就可以工作。如果我將if語句移動到with語句之上,它將起作用。

我在這種情況下做錯了什麼?

更新JSFiddle

+0

你想達到什麼目的?這是一個奇怪的淘汰賽模式,你正在使用... –

+0

我認爲*你的代碼是遵循這個執行路徑。 1.創建人視圖模型作爲可觀察到的,isPerson作爲可觀察和訂閱變化的人 2.把一個空物體插入人 3.將綁定與某甲 您的視圖模型4.超時,這次用一個沒有訂閱的全新可觀測數據覆蓋你的人。 5.執行上一個對象(不帶firstName)的訂閱函數。 –

+0

對不起,這是一個有點人爲的例子。最初,我有兩個稍微不同的對象,並且需要viewModel上的'person'來處理這兩個對象。 (更好的例子可能是personA = Customer和personB = Employee)。然後它開始擾亂我,我無法弄清楚它爲什麼不起作用。 –

回答

2

我不認爲你做錯了什麼。問題是在綁定到「with」之前正在應用root.isEmployee的「if」綁定。所以代碼看到isEmployee的更新,然後從那裏重新評估視圖,但當前的上下文仍然是舊的(因爲該訂閱沒有被解僱)。

這是通過http://jsfiddle.net/drdamour/X6pC9/2/中的自定義綁定來證明的,通知更新接收到2個事件,一次使用舊值導致isEmployee被更新,第二次更新新值。第二次更新來自觸發「綁定」訂閱。 'with'綁定的訂閱發生在applyBindings調用期間,這發生在您的模型執行訂閱之後。

您可以使用$ data.PropertyName技巧來處理undefined不會導致問題。阿拉:http://jsfiddle.net/drdamour/X6pC9/1/

<span data-bind="with: person"> 
    <span data-bind="text: firstName"></span> 
    <!-- ko if: $root.isEmployee --> 
     <span data-bind="text: $data.employeeId"></span> 
     <span data-bind="text: $data.employer"></span> 
    <!-- /ko -->  
</span> 

解決這個正確的方法是有具有isEmployee計算的PersonVM,你不綁定到root的方式。見:http://jsfiddle.net/drdamour/eVXTF/1/

<span data-bind="with: person"> 
    <span data-bind="text: firstName"></span> 
    <!-- ko if: isEmployee --> 
     <span data-bind="text: $data.employeeId"></span> 
     <span data-bind="text: $data.employer"></span> 
    <!-- /ko -->  
</span> 

var ViewModel = function(){ 
    var self = this; 
    self.person = ko.observable(); 
}; 

var PersonVM = function() 
{ 
    var self = this; 
    this.firstName = ko.observable(); 
    this.employeeId = ko.observable(); 
    this.employer = ko.observable(); 

    self.isEmployee = ko.computed(function(){return self.employer() != null}); 
} 

var vm = new ViewModel(); 
var customer = new PersonVM(); 
customer.firstName("John"); 

var employee = new PersonVM(); 
employee.firstName("Bill"); 
employee.employeeId(123); 
employee.employer("ACME"); 

vm.person(customer); 
ko.applyBindings(vm); 
setTimeout(function(){ vm.person(employee); }, 3000); 

計算是首選,因爲它與認購鏈涉及您訂閱的方法和從具有管理所有抽象你帶走。

+0

非常感謝。任何想法爲什麼$數據技巧的作品? –

+0

,因爲$ data可以被binder始終解析,並且你總是可以獲得一個不存在的對象屬性,它只是返回未定義的,並且文本綁定將未定義爲空文本。如果$ data是空的,它將不會工作......我想。 –

+0

+1。我的頭痛苦地試圖讓我的頭繞着ko綁定。 –