2012-04-13 85 views
25

是否有無論如何我可以告訴knockout貼圖插件訂閱所有的屬性更改調用某個函數?KnockoutJS訂閱屬性更改與映射插件

我知道我可以手動訂閱屬性更改事件以這種方式:

var viewModel = { 
    name: ko.observable('foo'), 
} 

// subscribe manually here 
viewModel.name.subscribe(function(newValue){ 
    // do work 
}) 

我希望能夠一般訂閱不過,因爲我的視圖模型可能會有所不同,我不想硬編碼屬性名稱。我創建了一個這樣做的函數,但它可能不是最好的方法。它適用於除IE7及以下版本以外的所有瀏覽器。

下面我就一個視圖模型作爲參數,並設法爲它訂閱屬性:

function subscribeToKO(data) { 

     $.each(data, function (property, value) { 
      if (getType(value) == "Object") 
       data[property] = subscribeToKO(value); 
      else if (getType(value) == "Array") { 
       $.each(value, function (index, item) { 
        item = subscribeToKO(item); 
       }); 
      } 
      else { 
       if (value.subscribe) { 
        value.subscribe(function (newValue) { 
         // do work           
        }); 
       } 
      } 
     }); 
     return data; 
    } 

就像我說的這個作品,但因爲我使用的映射pluging我希望有一個掛鉤我可以用它來提供一個一般會訂閱屬性更改的函數。

喜歡的東西:

mapping = { 
    create: function(options){ 
     options.data.subscribe(function(newValue){ 
      // do work ??? 
     }); 
    } 
} 

ko.mapping.fromJS(viewModel, mapping); 

任何想法?

回答

9

下面是一個基於Ryan Niemeyer's dirty flag的通用方法。
請點擊這裏查看JsFiddle

HTML:

<ol> 
<li> 
    Telephone : <input data-bind="value: telephone"/> 
</li> 
<li> 
    Address : <input data-bind="value: address"/> 
</li> 
</ol>​ 

的Javascript:

var model = { 
    telephone: ko.observable('0294658963'), 
    address: ko.observable('167 New Crest Rd') 

}; 
// knockout extension for creating a changed flag (similar to Ryan's dirty flag except it resets itself after every change) 
ko.changedFlag = function(root) { 
    var result = function() {}; 
    var initialState = ko.observable(ko.toJSON(root)); 

    result.isChanged = ko.dependentObservable(function() { 
     var changed = initialState() !== ko.toJSON(root); 
     if (changed) result.reset(); 
     return changed; 
    }); 

    result.reset = function() { 
     initialState(ko.toJSON(root)); 
    }; 

    return result; 
}; 
// add changed flag property to the model 
model.changedFlag = new ko.changedFlag(model); 
// subscribe to changes 
model.changedFlag.isChanged.subscribe(function(isChanged) { 
    if (isChanged) alert("model changed"); 
}); 
ko.applyBindings(model);​ 
3

這個方便的小插件是非常接近你做了什麼,但它提供了幾個選項,並且可以工作在更廣泛的一系列要求,而不需要Mapping插件:

https://github.com/ZiadJ/knockoutjs-reactor

基本上它可以讓你編寫這樣的代碼:

ko.watch(viewModel, function(target, trigger) { 
    // do work 
});