Understanding click binding in Knockout.js

Click Binding adds click event to element on View. You can do click binding with any function in ViewModel or you can bind to any normal function.

clip_image001

Let us try to understand it with a very simple ViewModel. We have a ViewModel as below

 var viewModel =
 {
 display: function ()
 {
 console.log("display");
 }
 }

As you see there is one function as property of ViewModel and that can be click bind on view as below,


<button data-bind="click:display" >display</button>

Let us consider one more example and in this we will update value of other observable on click of element on View. We have ViewModel as below,


var viewModel =
 {
 count : ko.observable(0) ,
 display: function ()
 {
 this.count( this.count() + 1);
 }
 }

On View we are doing click binding and text binding as below


<button data-bind="click:display" >display</button> <br/>
 Number of clicks <span data-bind="text:count" ></span>

Sometime you may have to pass current item in click binding. Assume a requirement that you have done foreach binding on element with observable array. Now on click of a particular item, you need to pass that item in ViewModel function to work with that. That can be solved as below. As you see in below ViewModel,

  • There is an observable array. This will be bind to ul or tr element on View
  • There is a function. It takes input which will be used to delete item from observable array.

function viewModel()
 {
 var self = this ;
 self.subject= ko.observableArray(["Phy", "Che", "Bio"]),
 self.removeSubject= function (item)
 {

 self.subject.remove(item);
 }
 }


ko.applyBindings(new viewModel());

On the View we need to do click binding and pass current item to function on which click binding is getting performed.


<ul data-bind="foreach: subject">
 <li>
 <span data-bind="text: $data"></span>
 <button data-bind="click: $parent.removeSubject">Remove</button>
 </li>
</ul>


If you notice we are passing current item using current binding context. So to pass current we are using parent.

In some scenario you will have to pass event object. Event object can be passed as given below,


function viewModel()
 {
 var self = this ;
 self.subject= ko.observableArray(["Phy", "Che", "Bio"]),
 self.removeSubject= function (data,event)
 {
 if (event.shiftKey) {
 self.subject.remove(data);
 }
 }
 }


On View binding can be done as below


<ul data-bind="foreach: subject">
 <li>
 <span data-bind="text: $data"></span>
 <button data-bind="click: $parent.removeSubject($data,event)">Remove</button>
 </li>
</ul>

&nbsp;

Now an item would be deleted on pressing shift key . Understanding of click binding is very useful to create apps using KO. I hope you find this post useful. Thanks for reading.

Working with OData and WinJS ListView in Metro Application

In this post we will see how to consume Netflix OData feed in HTML based Metro Application. Movies information will be displayed as following. At the end of this post, we should have output as below,

image

Netflix exposed all movies information as OData and that is publicly available to use. Netflix OData feed of movies are available at following location

http://odata.netflix.com/Catalog/

Essentially we will pull movies information from Netflix and bind it to ListView Control of WinJS. We will start with creating a blank application.

image

In the code behind (default.js) define a variable of type WinJS List.

image

Now we need to fetch the movies detail from Netflix. For this we will use xhr function of WinJS. As the parameter of function, we will have to provide URL of the OData feed.

image

In above code snippet, we are performing following tasks

  • Making a call to Netflix OData using WinJS .xhr function
  • As input parameter to xhr function, we are passing exact url of OData endpoint.
  • We are applying projection and providing JSON format information in URL itself.
  • Once JSON data is fetched form Netflix server data is being parsed and pushed as individual items in the WinJS list.

As of now we do have data with us. Now let us go ahead and create a ListView control. You can create WinJS ListView as following. Put below code on the default.html

clip_image002

In above code we are simply creating a WinJS ListView and setting up some basic attributes like layout and itemTemplate. Now we need to create Item Template. Template is used to format data and controls how data will be displayed. Template can be created as following

image

In above code, we are binding data from the data source to different HTML element controls. At last in code behind we need to set the data source of ListView

image

Before you go ahead and run the application just put some CSS to make ListView more immersive. Put below CSS in default.css

image

Now go ahead and run the application. You should be getting the expected output as following

image

Let us consolidate all the codes from discussion.

Default.html

<!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8" />
 <title>testdemo</title>

<!-- WinJS references -->
 <link href="//Microsoft.WinJS.1.0.RC/css/ui-dark.css" rel="stylesheet" />
 <script src="//Microsoft.WinJS.1.0.RC/js/base.js"></script>
 <script src="//Microsoft.WinJS.1.0.RC/js/ui.js"></script>

<!-- testdemo references -->
 <link href="/css/default.css" rel="stylesheet" />
 <script src="/js/default.js"></script>
</head>
<body>
 <h1>Netflix Movie Application</h1>
 <div id="moviesTemplate"
 data-win-control="WinJS.Binding.Template">
 <div style="width: 150px; height: 130px;">
 <img src="#" style="width: 100px; height: 100px;"
 data-win-bind="alt: title; src: picture" />
 <div>
 <h4 data-win-bind="innerText:title"></h4>
 </div>
 </div>
 </div>

<div id="movieListView"
 data-win-control="WinJS.UI.ListView"
 data-win-options="{itemTemplate : moviesTemplate,
 layout: {type: WinJS.UI.GridLayout} }">
 </div>

</body>
</html>

Code behind will have following codes

Default.js


// For an introduction to the Blank template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232509
(function () {
 "use strict";

 var app = WinJS.Application;
 var activation = Windows.ApplicationModel.Activation;
 WinJS.strictProcessing();
 var movieArray = new WinJS.Binding.List();
 app.onactivated = function (args) {

 if (args.detail.kind === activation.ActivationKind.launch) {
 if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
 // TODO: This application has been newly launched. Initialize
 // your application here.
 } else {
 // TODO: This application has been reactivated from suspension.
 // Restore application state here.
 }
 args.setPromise(WinJS.UI.processAll());

 WinJS.xhr({
 url: "http://odata.netflix.com/Catalog/Titles" +
 "?$format=json&$select=ShortName,BoxArt&$top=300"
 }).then(function (xhr) {
 var movies = JSON.parse(xhr.response).d;
 movies.forEach(function (i) {
 movieArray.push({
 title: i.ShortName,
 picture: i.BoxArt.MediumUrl
 });
 });
 });
 var lstMovies = document.getElementById("movieListView").winControl;
 lstMovies.itemDataSource = movieArray.dataSource;

 }
 };

app.oncheckpoint = function (args) {

 };

app.start();
})();

And CSS will be as following

default.css


body {
}

@media screen and (-ms-view-state: fullscreen-landscape) {
}

@media screen and (-ms-view-state: filled) {
}

@media screen and (-ms-view-state: snapped) {
}

@media screen and (-ms-view-state: fullscreen-portrait) {
}
.win-listview
 {
 height: 100%;
 width: auto;

 }
 .win-listview .win-container {
 margin: 10px;
 }
 .win-listview .win-container:hover {
 background-color: red;
 border-color: red;
 }
 .semanticZoomItem
{
 width: 130px;
 height: 130px;
 background-color: rgba(38, 160, 218, 1.0);
}

.semanticZoomItem .semanticZoomItem-Text
 {
 padding: 10px;
 line-height: 150px;
 white-space: nowrap;
 color: white;
 }

In this way we can work with OData and winJS ListView. I hope you find this post useful. Thanks for reading.

Nested ListBox binding in Silverlight and Windows Phone 7

While creating an application I came across a requirement when I had to put a listbox inside a list box and then I had bind that nested listbox dynamically.

For example say, entity class called Roles as below,



    public class Roles
    {
        public string RollName { get; set; }
    }


And you are using Role class in another entity class called Subscription as property


  public class Subscription
    {
        public string SubscriptionName { get; set; }
        public List<Roles> lstRoles { get; set; }
    }


We need to achieve,

image

There is function to return Data to bind to nested list box as below,



List<Subscription> GetDataToBind()
        {
           List<Subscription> lstSubscriptions = new List<Subscription>
                                                {
                                                   new Subscription
                                                   {
                                                       SubscriptionName ="Susbcription1",
                                                       lstRoles = new List<Roles>
                                                       {
                                                            new Roles
                                                            {
                                                                RollName = "Role1"
                                                            },
                                                             new Roles
                                                            {
                                                                RollName = "Role2"
                                                            },
                                                             new Roles
                                                            {
                                                                RollName = "Role3"
                                                            }
                                                       }
                                                   },
                                                   new Subscription
                                                   {
                                                   SubscriptionName ="Susbcription2",
                                                       lstRoles = new List<Roles>
                                                       {
                                                            new Roles
                                                            {
                                                                RollName = "Role1"
                                                            },
                                                             new Roles
                                                            {
                                                                RollName = "Role2"
                                                            },
                                                             new Roles
                                                            {
                                                                RollName = "Role3"
                                                            }
                                                       }
                                                   }
                                                };
           return lstSubscriptions;

        }


As of now we are ready with

  1. Entity class
  2. Data source

image

And there is one more property in of generic list type in entity class. To bind that you need to set item source of internal list box as binding.

image

Final XAML will be as below,



<ListBox Height="646" HorizontalAlignment="Left" Margin="6,19,0,0" Name="listBox1" VerticalAlignment="Top" Width="444" >

                <ListBox.ItemTemplate>
                    <DataTemplate>
                    <Grid x:Name="grdListItem" Width="440">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="201*"/>
                            <ColumnDefinition Width="239*" />
                        </Grid.ColumnDefinitions>
                            <Image Source="AzureLogo.png" Height="100" Width="100" Grid.Column="0" />
                            <TextBlock x:Name="txtSubscription" Grid.Column="1" Height="100" Margin="6,0" Text="{Binding SubscriptionName}" />

                        <ListBox x:Name="lstWebRoles" Grid.Column="1" Margin="10,0,0,0" ItemsSource="{Binding lstRoles}" >
                                <ListBox.ItemTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Vertical" >
                                    <TextBlock x:Name="txtRoles" Height="80" Width="220" Text="{Binding RollName}" />
                                </StackPanel>
                                  </DataTemplate>
                                 </ListBox.ItemTemplate>
                           </ListBox>

                    </Grid>
                    </DataTemplate>
                    </ListBox.ItemTemplate>
            </ListBox>



Eventually put item source of external list box as,



public MainPage()
        {
            InitializeComponent();
            listBox1.ItemsSource = GetDataToBind();
        }

In this post we discussed binding of nested listbox in Silverlight. I hope this post was useful. Thanks for reading.  Smile