Windows Store App Development Series: Part 17 – WinJS ListView Data Binding Using AngularJS [Metro / Modern App!]

Hello,

Followed by my previous article on data binding using AngularJS in a Windows Store App, George Nixon asked me via twitter if its possible to bind WinJS ListView using AngularJS framework with full metro / modern experience. My instant reply was, it should be.

Twit

After I replied, I unsuccessfully Bing’ed to get some reference on it. Then I tried Google, got few references, but all of them were based on non modern / metro UI like my previous article. Then I thought its definitely worth to build small metro app with WinJS ListView and use AngularJS framework to populate some data. Spent few hours on paper and in Visual Studio and hey, I did it.

Before we dive into the code to understand AngularJS binding to WinJS, I strongly recommend you to read all the data binding articles I have published in this series so far. These articles will help you to understand WinJS ListView data binding techniques and modification needs to be done in AngularJS file to make it work with a Windows Store App.

So hoping you already read previous articles, lets dive into the code.

function EmployeeController($scope) {

    var app = WinJS.Application;
    var dataList;
    var employeesList;

    employees = [
        { name: 'Scott Allen', company: 'OdeToCode' },
        { name: 'Dan Wahlin', company: 'The Wahlin Group' },
        { name: 'Scott Hanselman', company: 'Microsoft' },
        { name: 'John Papa', company: 'Pluralsight' },
    ];

    app.onactivated = function (args) {
        WinJS.UI.processAll();
    };

    app.onready = function () {
        dataList = new WinJS.Binding.List(employees);
        employeesList = document.getElementById('employeesListView').winControl;
        employeesList.itemDataSource = dataList.dataSource;
    }

    $scope.addEmployee = function () {
        dataList.push(
            { name: 'Prasad Honrao', company: 'Cognizant' },
            { name: 'Scott Guthrie', company: 'Microsoft' }
            );
    }

    app.start();
}

Lets understand above code

    • The employees array in EmployeeController contains employee data with employee name and company details. During application execution cycle, app.onready function gets called which creates a WinJS binding list based on employees array. Then we are binding the list to employeesListview control defined in view [default.html]
    • The addEmployee function adds two new employees to the binding list. Note that, we are adding it to $scope variable, so that it can be accessed from View. $scope acts as a glue between controller and view.
    • WinJS.UI.ProcessAll function processes all the declarative bindings defined in the View.

Lets understand HTML code now

<body ng-controller="EmployeeController">
    <div id="employeesListViewTemplate" 
         data-win-control="WinJS.Binding.Template">
        <div class="container">
            <div class="top" data-win-bind="innerText:name"></div>
            <div class="bottom" data-win-bind="innerText:company"></div>
        </div>
    </div>

    <div id="employeesListView"
        data-win-control="WinJS.UI.ListView"
        data-win-options="{itemTemplate: select('#employeesListViewTemplate')}">
    </div>

    <div id="appBar" 
         data-win-control="WinJS.UI.AppBar" 
         data-win-options="">
        <button
            ng-click="addEmployee()"
            data-win-control="WinJS.UI.AppBarCommand"
            data-win-options="{id:'cmdAdd',label:'Add Employees',icon:'add',
                section:'global',tooltip:'Add item'}">
        </button>
    </div>
</body>
  • Body tag sets ng-controller to EmployeeController, so that all the variables and functions added to $scope variable in EmployeeController are now accessible in this view.
  • Next we have defined WinJS ListView control employeeListView and associated it with employeeListViewTemplate. In the template definition we have setup the data binding to name and company model properties.
  • Application bar contains ‘Add Employees’ command button. We have setup Angular ng-click directive to the addEmployee method defined in EmployeeController. Note $scope makes it available in the View.

That’s all we need to do. Run the application. You should get output as below.

EmployeeList

Click on ‘Add Employees’ button on the App Bar. Application should add new employees [Prasad Honrao and Scott Guthrie] to the list and display output as follows.

NewEmployeeList

Before I conclude this article, just few things to note

  • To make easy to understand, I have merged default.js file and EmployeeController function in one JavaScript file. However, you can define multiple JavaScript files – one for Application specific functionality and other for EmployeeeController functionality, so that you can unit test EmployeeController separately.
  • I wanted to bind WinJs ListView using Angular ng-model syntax rather than WinJS data binding, however I was not able to do that, due to the way WinJS ListView supports data binding. So in this article I just tried to hook EmployeeController and App Bar command button events. If anyone has tried it, please do let me know. I will modify the article and source code accordingly.

With that, I would like to thank you for reading the article. Feel free to download application source code from GitHub.

Please let me know if it was useful to you.

5 Comments

  1. Mike Mastrangelo · August 9, 2013 Reply

    Hey Prasad,

    WinJS Dev here.
    I’m not really familiar with AngularJS but this might help you:

    WinJS ListView takes our WinJS.Binding.Template but it also takes a render function.
    For your example:

    1. Switch to have $http, $compile:
    function EmployeeController($scope, $http, $compile) {

    2. Inside app.onready = function () { add this:

    function renderItem(item) {
    var scope = $scope.$new();
    scope.name = item.data.name;
    scope.company = item.data.company;
    var elem = angular.element(‘{{ name }}{{ company }}’);
    var result = $compile(elem)(scope);
    scope.$apply();
    return result[0];
    };

    employeesList.itemTemplate = WinJS.UI.simpleItemRenderer(renderItem);
    // Same as:
    //employeesList.itemTemplate = function (itemPromise) {
    // return itemPromise.then(renderItem);
    //};

    I quickly looked into ng-templates but couldn’t find the magic 1 line of code to render a scope into them:

    {{ name }}
    {{ company }}

    Hopefully this gives you enough information to keep going.

    Best of luck,
    Mike Mastrangelo

    • Prasad Honrao · August 9, 2013 Reply

      Hi Mike,

      Thanks for your valuable input. I am planning to make some more changes to the source code and will definitely take your suggestion into consideration. I will update my article accordingly. Thanks again.

      Regards,
      Prasad Honrao

  2. Josh · November 3, 2013 Reply

    Check out: https://github.com/codemonkeychris/angular-winjs, it is a library to help use WinJS UI controls natively within an Angular app.

  3. pawel · March 31, 2014 Reply

    hi, I know this is a bit outdated post but my impression is that you really cannot mix angular with winJS-ui. the reason is that angular do not have concept of reusing control parts. so for example if you want to enclose win-js list as directive you will find that it will not play well with template function. and without using template function you can forgot about creating flexible directive.

    for each item (template) you need to create independed scope that is somehow connected to controller’s scope. using angular you cannot manage life-cycle of the scope you just created and thus you are going to leak memory.

    for simple scenarios like you showed here – yes it is possible to use angular. I still try to figure out how binding works in winJs :D

    @Josh have you used the library in production?

Leave a Reply