Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subscribe to changes to intermediate objects in a knockoutjs viewmodel

I have a large knockout viewModel of which this is a JSON representation:

...
existingPlans: {
    startDate: "2014-11-01",
    endDate: "2017-03-01",
    plans: [
        {
            "customTitle": "plan 1 name",
            "monthlyPayments": [ 15000, 15000, 15000, 15000, 15000, 15000 ],
            "futureBalance": [ 90000, 75000, 60000, 45000, 30000, 15000 ]
        },
        {
            "customTitle": "plan 2 name",
            "monthlyPayments": [ 7000, 7000, 7000, 7000 ], 
            "futureBalance": [ 28000, 21000, 14000, 7000 ]
        }
    ]
}
...

StartDate and endDate are observables and plans is an observableArray. What I'd like to do is create one binding that fires when any of these three observables changes so on the level of "existingPlans".

I could make a computed field that depends on all three, but isn't there an easier way of doing this?

Something like the example below does not work since existingPlans itself cannot be observable (right?)

viewModel.existingPlans.subscribe(function(newValue) {
    // do stuff with newValue.startDate(), etc
})
like image 307
Koen Peters Avatar asked Apr 09 '26 09:04

Koen Peters


2 Answers

It depends on what should happen when these properties change. If you just want to trigger an event or something similar you could subscribe to the properties and use the same subscription handler for them, like this

function ExistingPlans() {
    this.startDate = ko.observable();
    this.endDate = ko.observable();
    this.plans = ko.observableArray();

    this.startDate.subscribe(this.handleChange, this);
    this.endDate.subscribe(this.handleChange, this);
    this.plants.subscribe(this.handleChange, this);                       
}

ExistingPlans.prototype.handleChange = function () {
    // do stuff
};

If you need to calculate something or present some result from the value of the properties I would create a computed observable.

like image 180
lagerone Avatar answered Apr 11 '26 21:04

lagerone


Since you're dealing with three different observables, you can't use a manual subscription. A computed observable is the way to go. A computed observable automatically watches all observables you access, and so will just work:

ko.computed(function() {
    // do stuff with existingPlans.startDate(), etc
});

If you want to absolutely make sure you're subscribed to all of the observables in a view model, you can use ko.toJS:

ko.computed(function() {
    ko.toJS(existingPlans);
    // do stuff with existingPlans.startDate(), etc
});
like image 27
Michael Best Avatar answered Apr 11 '26 21:04

Michael Best