Thursday, 6 August 2015

Knockout - Assignment of Observable Property

If you are a beginner in Knockout JS, this post can be very useful for you.

Problem

Have you ever came across a scenario or wondered why your observable property is not working as expected? 
It is very frustrating that after spending hours while writing your client side code, HTML binding is not working properly. After debugging the code, it is revealed that the cause of the problem is with the assignment of the observable property.
I have seen it many times that programmers with novice Knockout skillset are making this mistake which can be avoided by following correct rule of assignment and will save a lot of precious timeJ.

Scenario

Consider a very basic view model for book bookModel and with one observable property as bookName.
var bookModel = function () {
var that = this;
        that.bookName = ko.observable();
};
Snippet 1: Book View Model Definition
The structure of HTML markup with which we are going to bind instance of bookModel is as follows:
<div id="bookPanel">
        <div id="bookForm">
               <h1>Book Form</h1>
               <input data-bind="value: bookName" />
        </div>
        <hr />
        <div id="bookReview">
               <h1>Book Preview</h1>
               <h2 data-bind="text: bookName"></h2>
        </div>
</div>
Snippet 2: HTML markup
In order to create instance of book view model bookModel and bind it with the DIV tag in the markup having ID bookPanel following code can be used:
var bookObj = new bookModel();
bookObj.bookName = "Lord of the rings.";
ko.applyBindings(bookObj, $("#bookPanel")[0]);
Snippet 3: Model Binding
We are all setup with the required changes in the code and ready to test it in the browser.  So let’s try.
The screenshot below shows the output of above mentioned code in Google Chrome.


Figure 1: Output in Google Chrome when page is loaded
It seems that everything is working correctly.  Book name “Lord of the rings” is shown as expected in the input control and as well as in heading (H2 tag).  Let us try to update the value using the input control. 
Wait a minute, changing the value from the input control is not updating the text for the heading tag at all.  As shown below, the updated value in the input “The Hobbit” is not reflected in the heading tag.


Figure 2: Output in Google Chrome when updating value of input is not impacting heading
Let’s examine snippet 3 again used in this post.

var bookObj = new bookModel();
bookObj.bookName = "Lord of the rings.";
ko.applyBindings(bookObj, $("#bookPanel")[0]);
Snippet 3: Model Binding
Assignment done for bookName in the 2nd line of this snippet is the culprit.  It is actually overwriting the observability provided by Knockout and assigning “Lord of the rings” string value to the property. 
So let’s correct our code. Corrected line is highlighted below in snippet 4:
var bookObj = new bookModel();
bookObj.bookName("Lord of the rings.");
ko.applyBindings(bookObj, $("#bookPanel")[0]);
Snippet 4: Correct Code for Model Binding

Solution

From the snippet 4, it can be seen that in order to assign a value to the observable, call the observable (with in parenthesis brackets just like calling a function or method) and pass the new value as a parameter.

Complete Code

<script type="text/javascript">
       var bookModel = function () {
var that = this;
             that.bookName = ko.observable();
       };

       $(document).ready(function () {
             var bookObj = new bookModel();
             bookObj.bookName("Lord of the rings.");
             ko.applyBindings(bookObj, $("#bookPanel")[0]);
       });
</script>

<div id="bookPanel">
       <div id="bookForm">
             <h1>Book Form</h1>
             <input data-bind="value: bookName" />
       </div>
       <hr />
       <div id="bookReview">
             <h1>Book Preview</h1>
             <h2 data-bind="text: bookName"></h2>
       </div>
</div>
Snippet 5: Complete Code
Thanks for reading!


No comments:

Post a Comment