DCSIMG
December 2011 - Posts - Ran Wahle's blog

Ran Wahle's blog

December 2011 - Posts

KnockoutJS–Dependencies

KnockoutJS–Dependencies

KnockoutJs

One of the things we’ll probably need is to be able to have dependency tracking in our bounded data. For example – if we have a customer’s list, we’d like to see the customer’s orders whenever we click on a customer. In this post I’ll demonstrate how to do it using the dependentObservable function of KnockoutJS

Let’s look at the following JavaScript code:

   var viewModel = {
            customers: ko.observableArray([]),
            selectedCustomer: ko.observable(),
            orders: ko.observableArray([]),
 
            order: function () {
                return { itemName: "", description: "", unitPrice: 0, units: 0 }
            },
 
            customer: function () {
                return { firstName: "", lastName: "", joinedDate: new Date(), orders: ko.observableArray([this.order()]) }
            },
 
          
            addOrder: function () {
                this.orders.push(this.order());
            },
            addCustomer: function () {
                this.customers.push(this.customer());
            },
            setSelectedCustomer: function(customer)
            {
                this.selectedCustomer(customer);
               
            }
 
        };

In here, I’ve declared two data structures: customer and order. I’ve also exposed two data members: customers and orders which have the types above respectively. I’ve also exposed the selectedCustomer data-member which will be used for us in the future.

Now, let’s go to our HTML content.

In here we’ll have two tables – one for customers and one for orders. We’ll use templates for our data binding so it will look like that:

<body>
 <table>
 <thead>
 <tr>
 <th>
    First Name
 </th>
 <th>
    Last Name
 </th>
 <th>
    Joined Date
 </th>
 </tr>
 </thead>
 <tbody data-bind="template : {name: 'customersTemplate', foreach: customers}"></tbody>
 </table>
 <button data-bind="click: function() {viewModel.addCustomer()}">Add customer</button>
 <table>
 <tbody data-bind="template: {name: 'ordersTemplate', foreach: orders}">
</tbody>
 </table>
 <button data-bind="click: function() {viewModel.addOrder()}">Add Order</button>
 <script type="text/html" id="customersTemplate">
 <tr data-bind="click: function() {viewModel.setSelectedCustomer($data)}">
    <td>
        <input type="text" data-bind="value: firstName" />
        </td>
        <td>
          <input type="text" data-bind="textvalue: lastName" />
    </td>
    <td>
        <input type="datetime-local" data-bind="value: joinedDate"/>
    </td>
 </tr>
 </script>
 
  <script type="text/html" id="ordersTemplate">
 <tr>
    <td>
        <input type="text" data-bind="value: itemName" />
        </td>
        <td>
          <input type="text" data-bind="value: description" />
    </td>
    <td>
        <input type="text" data-bind="value: unitPrice"/>
    </td>
    <td>
        <input type="text" data-bind="value: units"/>
    </td
 </tr>
 </script>

You can notice from the HTML another three things:

1. There’s a button to add customer, when clicked it calls the addCustomer function
2. There’s a button to add order, when clicked it calls the addOrder function.
3. Whenever a customer row clicked, the setSelectedCustomer function is called.
   All setSelectedCustomer does is assign the customer who’s row was clicked on, to the
   selectedCustomer
data member. The dependentObservable function will do the rest.

All of that is achieved using the event bindings of KnockoutJS

 

Now, Let’s have dependencies between the selected costumer and it’s orders:

    ko.dependentObservable(function () {
              if (this.selectedCustomer()) {
                this.orders(this.selectedCustomer().orders());
     }
        }, viewModel); 

What does it do? whenever the selectedCustomer member is changed, it assigns it’s orders to the orders data member, and that’s how we’ve achieved dependencies between the customer and it’s order.

In the function of it’s first parameter, we can have all our dependency tracking code (and that’s all our dependency tracking). The word “this” inside  the function refers to the view-model we’ve provided on the second parameter.

Summary

Dependency tracking is something we’d probably want when having data binding with complex data (parent-child structures for example), having master-details view or even computed values. The dependentObservable function of KnockoutJS allows as to do so in a very easy manner. All we have to do is plant our code in the function at it’s first parameter and well… that’s it.

Here is the full example:

<!DOCTYPE HTML>
<html>
<head>
    <title></title>
    <script type="text/javascript" src="../scripts/jquery-1.6.2.min.js"></script>
    <script type="text/javascript" src="../scripts/jquery.tmpl.min.js"></script>
    <script type="text/javascript" src="../scripts/knockout-latest.js"></script>
    <script type="text/javascript">
        var viewModel = {
            customers: ko.observableArray([]),
            selectedCustomer: ko.observable(),
            orders: ko.observableArray([]),
            customerFirstName: ko.observable(),
            order: function () {
                return { itemName: "", description: "", unitPrice: 0, units: 0 }
            },
 
            customer: function () {
                return { firstName: "", lastName: "", joinedDate: new Date(), orders: ko.observableArray([this.order()]) }
            },
 
 
            addOrder: function () {
                this.orders.push(this.order());
            },
            addCustomer: function () {
                this.customers.push(this.customer());
            },
            setSelectedCustomer: function (customer) {
                this.selectedCustomer(customer);
            }
          
 
        };
 
        ko.dependentObservable(function () {
 
            if (this.selectedCustomer()) {
                this.orders(this.selectedCustomer().orders());
            }
        }, viewModel); 
      
        
    </script>
</head>
<body>
 <span data-bind="text: customerFirstName"></span>
    <table>
        <thead>
            <tr>
                <th>
                    First Name
                </th>
                <th>
                    Last Name
                </th>
                <th>
                    Joined Date
                </th>
            </tr>
        </thead>
        <tbody data-bind="template : {name: 'customersTemplate', foreach: customers}">
        </tbody>
    </table>
    <button data-bind="click: function() {viewModel.addCustomer()}">
        Add customer</button>
    <table>
        <tbody data-bind="template: {name: 'ordersTemplate', foreach: orders}">
        </tbody>
    </table>
    <button data-bind="click: addOrder">
        Add Order</button>
    <script type="text/html" id="customersTemplate">
 <tr data-bind="click: function() {viewModel.setSelectedCustomer($data)}">
    <td>
        <input type="text" data-bind="value: firstName" />
        </td>
        <td>
          <input type="text" data-bind="value: lastName" />
    </td>
    <td>
        <input type="datetime-local" data-bind="value: joinedDate"/>
    </td>
 </tr>
    </script>
    <script type="text/html" id="ordersTemplate">
 <tr>
    <td>
        <input type="text" data-bind="value: itemName" />
        </td>
        <td>
          <input type="text" data-bind="value: description" />
    </td>
    <td>
        <input type="text" data-bind="value: unitPrice"/>
    </td>
    <td>
        <input type="text" data-bind="value: units"/>
    </td
 </tr>
    </script>
    <script type="text/javascript">
 
        ko.applyBindings(viewModel);
   
    </script>
</body>
</html>
kick it on DotNetKicks.com

KnockoutJS–Event binding

KnockoutJS–Event binding

KnockoutJs

After binding the data into our page, we wish to be able to create an interactive page. This means that we want to be able to add some behavior to our view-model, triggered by an event on the page. (A button being clicked for example).

The click binding

You can bind to the click binding the same as you bind to the value only that now it’s expects a parameter-less function. In case you have a method that expect parameters you can have a binding expression like that:

 <button data-bind="click: function() {viewModel.setSelectedCustomer(yourParameter)}">Set customer </button>

On that binding you’re operating a function on your view-model triggered by the button click.

The click binding is not restricted to buttons of course, you can triggered event for every clickable HTML element.

The event binding

If you wish to bind to another events such as mouseover, keypress etc. you need an event-binding. It’s syntax is slightly different but there isn’t a big change.

All events you wish to bind are to be kept inside one block ({event1: handler, event2: handler }) every handler is a parameter-less function however you can bind to an expression the same as the click binding above.

See below, example for event binding with mouseover and mouseout:

<input type="text" 
data-bind="value: channelUrl, event: {mouseover: function() {viewModel.title('Get Items')}, mouseout : function() {viewModel.title('')}}" />

Summary

In order to add interactivity to our page (otherwise it won’t be an application) we need to bind events to functions on our view-model. The function expected to be bound are ones without parameters however we can bind to an expression by having the event name, followed by the function() keyword and then, our Javascript expression.

When the event is fired, the bounded function on our view-model will execute. On that function we ought to change another bounded data, call server side by AJAX and so on.

kick it on DotNetKicks.com

KnockoutJS–Templates

KnockoutJS–Templates

After being introduced KnockoutJsto KnockoutJS concept and go to know the
basics of data-binding with Observable and 
observableArray, let’s move on to how to work with templates and our collection to them.

In this post I’ll explain how to bind a collection with template.

Prerequisites

Now, adding to KnockoutJS Prerequisites (jQuery 1.4.2 and above)  you’ll need another Javascript library: jQuery.tmpl . You can download this version or visit the project page for latest version.

HTML as script

The templates are HTML content written inside of a script tag, and it looks like that:

 <script type="text/html" id="itemsTemplate">
<!-- Your HTML template content here -->
 </script>

The script tag has an ID, it will be used to associate the template to a place in a document where it should be presented

Associate the template

The following HTML element (Unordered list in here) will be associated to the template, as below. the template binding has tow main attributes: name to associate with the template (corresponds to the ID attribute of the template above) and the foreach which corresponds to the observableArray member of the view-model we’d like to bind.

<ul data-bind='template: {name: "itemsTemplate", foreach: rssItems} '>
    </ul>

Now, the HTML element is associated with a template and bounded to a data member.
Let’s have a look inside the template:

Binding inside the template

Binding inside the template is very similar to regular binding, only that we bind to and item within a collection instead of binding to a data member inside our view-model.

In order to bind data where there is no suitable type for us (Assign a css class to an input element according to the item’s data) we can use the ($data) expression which points at the whole bounded item and have a JavaScript expression with it, as seen at the example below: (For our XAML friends – let’s say that this is a converter)

  <input type="text" data-bind="css:{selectedCustomerClass : ($data) == viewModel.selectedCustomer()}"/>

Summary:

After heaving simple binding we’d like to bind a collection and as we did in every other technology (ASP.Net, WPF, WinForm you name it…) we need a template to bind it to.

Heaving included the template JavaScript library of jQuery.tmpl, we can now write our own templates and bind it to our observableArray .

kick it on DotNetKicks.com