A simple, clean way to synchronize observables from different viewing models

Say I have two presentation models, each of which has an observable property that represents different but similar data.

function site1Model(username) {
    this.username = ko.observable(username);
    ....
}

function site2Model(username) = {
    this.username = ko.observable(username);
    ....
}

These viewing models are independent and not necessarily related to each other, but in some cases the third view model creates a connection between them.

function site3Model(username) = {
    this.site1 = new site1Model(username);
    this.site2 = new site2Model(username);
    // we now need to ensure that the usernames are kept the same between site1/2
    ...
}

Here are some options I came up with.

  • Use a computed observable that reads one and writes both:

    site3Model.username = ko.computed({
        read: function() {
            return this.site1.username();    // assume they are always the same
        },
        write: function(value) {
            this.site1.username(value);
            this.site2.username(value);
        },
        owner: site3Model
    }
    

    This will maintain synchronized values ​​if there are always changes in the calculation. But if the underlying observable changes directly, it will not.

  • Use the method subscribeto update each of the other:

    site3Model.site1.username.subscribe(function(value) {
        this.site2.username(value);
    }, site3Model);
    site3Model.site2.username.subscribe(function(value) {
        this.site1.username(value);
    }, site3Model);
    

    , , ; . : if (this.site1.username() !== value) this.site1.username(value); , ( , site1 site2 ).

  • computed :

    site3Model.username1Updater = ko.computed(function() {
        this.site1.username(this.site2.username());
    }, site3Model);
    site3Model.username2Updater = ko.computed(function() {
        this.site2.username(this.site1.username());
    }, site3Model);
    

    . , site1 site2 , this.site1().username(this.site2().username()); , . , , , , ( - observable.peek). , ( computed).

, , , ( 10 ), ( ) ( )?

+5
4

, . , , pub/sub.

, , subscribe, , . . , , . , , . , , , .

function subscribeObservables(source, target, dontSetInitially) {
    var sourceObservable = ko.isObservable(source) 
            ? source 
            : ko.computed(function(){ return source()(); }),
        isTargetObservable = ko.isObservable(target),
        callback = function(value) {
            var targetObservable = isTargetObservable ? target : target(); 
            if (targetObservable() !== value)
                targetObservable(value);
        };
    if (!dontSetInitially)
        callback(sourceObservable());
    return sourceObservable.subscribe(callback);
}

function syncObservables(primary, secondary) {
    subscribeObservables(primary, secondary);
    subscribeObservables(secondary, primary, true);
}

20 , , , 10 .: -)

, : http://jsfiddle.net/mbest/vcLFt/

+5

10 ( ), pub/sub .

, : https://github.com/rniemeyer/knockout-postbox

, ko.subscribable . , subscribeTo, publishOn syncWith ( , ). , .

pubsub. , .

, 10 . , , , (equalComparer), .

.

: http://jsfiddle.net/rniemeyer/mg3hj/

+7

- , . viewmodels datacontext , . VM datacontext, . , . , , pub/sub.

pub/sub, Ryan Niemyer, , amplify.js, / ( ). .

+1

If necessary. Another option is to create a reference object / observable. It also processes an object that contains several observables.

(function(){
    var subscriptions = [];

    ko.helper = {
        syncObject: function (topic, obj) {
            if(subscriptions[topic]){
                return subscriptions[topic];
            } else {
                return subscriptions[topic] = obj;
            }
        }
    };
})();

In your models.

function site1Model(username) {
    this.username = syncObject('username', ko.observable());
    this.username(username);
    ....
}

function site2Model(username) = {
    this.username = syncObject('username', ko.observable());
    this.username(username);
    ....
}
0
source

All Articles