web-dev-qa-db-ja.com

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;
    }

私が言ったように、これは機能しますが、マッピングプラグインを使用しているので、プロパティの変更を一般的にサブスクライブする関数を提供するために使用できるフックがあることを期待していました。

何かのようなもの:

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

ko.mapping.fromJS(viewModel, mapping);

何か案は?

25
Gabe

Ryan Niemeyerのダーティフラグ に基づく一般的なアプローチを次に示します。
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);​
9
Matthew Kelly

この便利な小さなプラグインは、あなたがやったことにかなり近いですが、いくつかのオプションが付属しており、マッピングプラグインを必要とせずにはるかに幅広い要件のセットを処理できます。

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

基本的に、次のようなコードを記述できます。

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