In this post we will take a look on Computed Observable in Knockout.js. Let us start with an example, you have a ViewModel


var viewModel =
 {
 name: ko.observable("G Block"),
 age: ko.observable(40)
 };

Now you want a custom message to be rendered on the view, that message will depend on other observable of ViewModel. To create that custom message you need to create a Computed Observable. Computed Observable can be created as below,

image

It takes two required parameter,

  • First parameter as function. This function will work with other observable and calculate computed observable
  • Second parameter is name of the function. If you are creating computed observable inside ViewModel then second parameter should be this

So ViewModel with computed observable is as follows,


var viewModel =
 {

name: ko.observable("G Block"),
 age: ko.observable(40),

 };

viewModel.greet = ko.computed(function () {
 return this.name()
 + " is " +
 this.age() +
 " years old";
 }, viewModel);

 ko.applyBindings(viewModel);

On View binding can be done as follows,

 


<input type="text" data-bind="value:name" />
 <input type="text" data-bind="value:age" /> <br />
 <span data-bind="text:greet" />

Few points worth knowing about computed observable

  • It gets evaluated as soon as the computed observable is created. So we may get into problem in a scenario in which computed observable is based on properties which not yet computed or initialized or loaded.
  • If computed observable is based on simple property (not observable property) then change in property will not trigger change in computed observable
  • Change in computed observable triggers if any of the observable property it is based on gets changed.

Computed observable can be created in one more ways as well. You can create ViewModel as below,


function viewModel() {
 var self = this;
 self.name = ko.observable("G Block");
 self.age = ko.observable(40);
 self.greet = ko.computed(function () {
 return self.name()
 + " is " +
 self.age() +
 " years old";
 }, this);
 };

As you notice that we have added computed observable as part of ViewModel. If you follow this way of creating ViewModel then you need to manage this explicitly. We are passing second parameter as this. Without passing it we can’t evaluate computed observable and cannot access other observable to calculate computed observable. So if you don’t pass this as second parameter, you won’t able to access this.age() and this.name(). In above scenario we are preserving this in self inside ViewModel and using self instead of this.

Writeable Computed Observable

So far we have created computed observable reading values of other observables and then returning value based of them. These observables are Read-Only Computed Observable.

You can create writeable Computed Observable as well. You wish to create writeable computed observable in following possible scenarios

  • Interpreting user input
  • Validating user input
  • Setting values of other observables on based on some logic

So let us see how we can use writeable computed observable. Let us say you have a view as below,

clip_image001

Requirements are,

  • When you change run Average should get updated.
  • Average is computed observable and based on Runs and Match

We can achieve above requirement by creating a simple ViewModel and a read only computed observable.

One of other requirement is that when you change Average, Runs should get updated. This can be done by creating a writeable observable.

Let us start with creating a ViewModel,


var playerViewModel =
 {
 name: ko.observable("Sachin T"),
 runs: ko.observable(10000),
 match: ko.observable(100)
 };

Now we need to create a writeable computed observable.


playerViewModel.average = ko.computed({
 read: function ()
 {
 var avg = this.runs() / this.match();
 return avg;
 },
 write: function (value)
 {
 var r = value * this.match();
 this.runs(r);
 },
 owner: playerViewModel
 });

To create writeable computed observable

  • You need to pass JavaScript object to ko.computed function
  • That takes options like read, write, owner etc.
  • Read property takes a function and return value based on other observable
  • Write property also take a function as input. This function take an input parameter “value”. You may wish to perform operation on value and write back resulted value to other observable.
  • You need to ViewModel as owner. This defines the reference of the key

image

In this way you can create writeable computed observable. You can bind values to View as below,


<span data-bind="text:name"></span> <br />
 Runs: <input type="text" data-bind="value:runs" /> <br />
 Match: <input type="text" data-bind="value:match" /> <br />
 Average: <input type="text" data-bind="value:average" />

Deferred Evaluation of computed observable

Before we end this post let us discuss one more concept of deferred execution of computed observable. As we discussed in beginning of this post that computed observable get evaluated at time of creation. So if it is based on observable which is not loaded at time of creation of computed observable then you might run into problem. KO gives you option to deferred execution of computed observable. You can do that by setting deferEvaluation value to true

image

We learnt in this post about Computed Observable. I hope you find this post useful. Thanks for reading.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s