Handling click event on elements within WinJS Listview ItemTemplate

Published May 29, 2013 5:26 pm

Typically – there is need to handle ‘itemInvoked’ event in a ListView. but there are some cases when you are looking for handling click event on a element defined in list view item template. Since item template is rendered multiple times for each item in the list view, how do we do this?

Let’s take an example where item template has two anchors. On click on each anchor, you want to tranverse to another page but parameter passed to the page will differ based on which anchor was clicked.

<div id="itemTemplate" data-win-control="WinJS.Binding.Template">
    <div>
        <h3 class="win-type-ellipsis date cell" data-win-bind="innerText: date"></h3>
        <h3 class="win-type-ellipsis hour cell" data-win-bind="innerText: hour"></h3>
        <a class="win-type-ellipsis counter1 cell" data-win-bind="innerText: counter1" ></a>
        <a class="win-type-ellipsis counter2 cell" data-win-bind="innerText: counter2" ></a>
    </div>
</div>

To do this, we need to register a wrapper itemTemplate function in code like this. That will enable us to register event handlers for counter1 and counter2 cells.

    listView.winControl.itemTemplate = this._itemTemplate.bind(this);
    _itemTemplate: function itemTemplate(itemPromise)
    {
        var self = this;
        var container = document.createElement('div');
        return itemPromise.then(function onitem(item)
        {
            return itemTemplate.winControl.render(item.data, container);
        }).then(function onrendercompete(c)
        {
            // register event listener
            var counter1Element = c.querySelector('.counter1);
            var counter2Element = c.querySelector('.counter2);
            counter1Element.onclick = self._oncounter1click.bind(self);
            counter2Element.onclick = self._oncounter2click.bind(self);
            return container;
        });
    },

In the event handler, we can use ListView.indexOfElement() method to get the item corresponding to the element clicked.

    _oncounter1click: function oncounter1click(event)
    {
        this._navigateToRequestsPage(event.currentTarget, 'counter1');
    },
    _oncounter2click: function oncounter2click(event)
    {
        this._navigateToRequestsPage(event.currentTarget, 'counter2');
    },
    _navigateToRequestsPage: function navigateToRequestsPage(itemElement, counterFlag)
    {
        var index = hourlyStatListView.winControl.indexOfElement(itemElement);
        var item = this.viewModel.items.getAt(index);
        var hour = item.date + 'T' + item.hour;
        WinJS.Navigation.navigate('/pages/itemDetails/itemDetails.html', { hour: hour, counterFlag: counterFlag});
    }

In summary, we saw how we can use wrapper item template function to register event handlers with elements declared within item template. We also saw the use and relevance of ListView.indexOfElement() function in the scenario.