locked
Problem with Group Title not firing onClick event?

    Question

  • Hey Guys,

    In the Grid Template I have a group title as below with the onclick event binded. However when I click the group title, nothing fires at all. Doesn't look like I'm missing anything. Looked at the console and there are no javascript errors. It should fire the click function and navigate to the page specified.

    HTML

    <div class="headerTemplate" data-win-control="WinJS.Binding.Template">
            <h2 class="group-title" data-win-bind="onclick: click; textContent: title" role="link"></h2>
    </div>
    Javascript

    (function () {
        "use strict";
    
        var appView = Windows.UI.ViewManagement.ApplicationView;
        var appViewState = Windows.UI.ViewManagement.ApplicationViewState;
        var nav = WinJS.Navigation;
        var ui = WinJS.UI;
        var utils = WinJS.Utilities;
    
    
        ui.Pages.define("/html/groupedItemsPage.html", {
    
    
            groupDataSelector: function (item) {
                return {
                    title: item.group.title,
                    click: function () {
                        nav.navigate("/html/groupDetailPage.html", { group: item.group });
                    }
                } 
            },
            
            // This function is used in updateLayout to select an item's group key.
            groupKeySelector: function (item) {
                return item.group.key;
            },
    
            itemInvoked: function (eventObject) {
                if (appView.value === appViewState.snapped) {
                    // If the page is snapped, the user invoked a group.
                    var group = data.groups.getAt(eventObject.detail.itemIndex);
                    nav.navigate("/html/groupDetailPage.html", { group: group });
                } else {
                    // If the page is not snapped, the user invoked an item.
                    var item = data.items.getAt(eventObject.detail.itemIndex);
                    nav.navigate(item.pageTo, { item: item });
                }
            },
    
            // This function is called whenever a user navigates to this page. It 
            // populates the page elements with the app's data.
    
            ready: function (element, options) {
    
                //document.getElementById('zoomedInListView').addEventListener("click", this.handler, false);
                var listView = element.querySelector("#zoomedInListView").winControl;
    
                    ui.setOptions(listView, {
                        itemTemplate: element.querySelector(".itemtemplate"), 
                        oniteminvoked: this.itemInvoked.bind(this)
                    });
    
                   // make the win-horizontal control move left and right for mouse wheel
                    var listViewScrollControl = element.querySelector("#zoomedInListView");
                    listViewScrollControl.addEventListener("mousewheel", function (ev) {
                        var scroller = listViewScrollControl.querySelector(".win-horizontal");
                        if (scroller) {
                            scroller.scrollLeft -= ev.wheelDelta;
                            return false;
                        }
                    });
    
                /*
                this.updateLayout(element, appView.value);
                */
            },
    
            // This function updates the page layout in response to viewState changes.
            updateLayout: function (element, viewState) {
                var listView = element.querySelector(".zoomedInListView").winControl;
                if (viewState === appViewState.snapped) {
                    // If the page is snapped, display a list of groups.
                    ui.setOptions(listView, {
                        itemDataSource: data.groups.dataSource,
                        groupDataSource: null,
                        layout: new ui.ListLayout()
                    });
                } else {
                    // If the page is not snapped, display a grid of grouped items.
                    var groupDataSource = data.items.createGrouped(this.groupKeySelector, this.groupDataSelector).groups;
    
                    ui.setOptions(listView, {
                        itemDataSource: data.items.dataSource,
                        groupDataSource: groupDataSource.dataSource,
                        layout: new ui.GridLayout({ groupHeaderPosition: "top" })
                    });
    
                    ui.setOptions(listViewZoomed, {
                        groupDataSource: data.items.groups.dataSource,
                        layout: new ui.GridLayout({ groupHeaderPosition: "top" })
                    });
                }
            },
    
        });
    
    
    })();
    


    Wednesday, May 16, 2012 11:20 AM

All replies

  • Hi Solar,

    You are hiding you click event in an anonymous function.  Any thing defined inside a function is only accessible to that function and not global in scope.  This has a section dedicated to the subject Quickstart: adding HTML controls and handling events.  See the section: Why you shouldn't set an event handler in markup.  After reading it you will understand why click does not work and how to fix it!

    -Jeff


    Jeff Sanders (MSFT)

    Wednesday, May 16, 2012 12:27 PM
    Moderator
  • Hi Jeff,

    I initially thought that and used a namespace like this:

    HTML:

        <div class="headerTemplate" data-win-control="WinJS.Binding.Template" >
            <h2 class="group-title" data-win-bind="onclick: startPage.clickEventHandler; textContent: title"  role="link"></h2>
        </div>


    Javascript:

    (function () {
    ...   
    
     function handler() {
    
            // execute nav
        }
    
        var namespacePublicMembers = { clickEventHandler: handler };
        WinJS.Namespace.define("startPage", namespacePublicMembers);
    
    })();
    Still nothing fires and it should now be visible to the onclick event in the html.


    • Edited by Solarpitch Wednesday, May 16, 2012 12:40 PM
    Wednesday, May 16, 2012 12:39 PM
  • Really not understanding this:

    Going by documentation, I'm now trying:

    JS

                    var link = element.querySelector(".grouplink");
                    link.addEventListener("click", function (ev) {
    
                       // ececute code
                    });

    HTML

        <div class="headerTemplate" data-win-control="WinJS.Binding.Template" >
            <h2 class="grouptitle" data-win-bind="textContent: title"  role="link"></h2>
        </div>
    Still having issue trying to get this thing to fire.


    • Edited by Solarpitch Wednesday, May 16, 2012 3:32 PM
    Wednesday, May 16, 2012 3:32 PM
  • Your original code looks like it is straight out of the Grid Template (which works for me.)

    What did you change in the template?  That is where you are likely to find the problem.


    • Edited by jrboddie Wednesday, May 16, 2012 3:54 PM
    Wednesday, May 16, 2012 3:53 PM
  • Only change I've made is this:

    Commented out this:

        //var list = new WinJS.Binding.List();
        //var groupedItems = list.createGrouped(groupKeySelector, groupDataSelector);
    
        //// TODO: Replace the data with your real data.
        //// You can add data from asynchronous sources whenever it becomes available.
        //sampleItems.forEach(function (item) {
        //    list.push(item);
        //});
    
    
    Added This:
        var list = getvideoResults();
        var groupedItems = getGroupedData();
    
        WinJS.Namespace.define("data", {
            items: groupedItems,
            groups: groupedItems.groups,
            getItemsFromGroup: getItemsFromGroup
        });


    Wednesday, May 16, 2012 4:14 PM
  • Not seeing your getvideoResults() method, it is hard to say.

    Can you keep the first two lines as they were and structure the code in the TODO section to push your video results objects into the list object like in the template?

    Wednesday, May 16, 2012 5:01 PM
  • This is what the whole data.js looks like. It's pretty similar to one of the example in the documentation thats why I've done it this way, commenting out those two lines as suggested.

    Not sure how anything I have here is stopping the click event from firing. The click event for the llist view items fire fine.

    (function () {
        "use strict";
    
        // Set up array variables
    
        var dataPromises = [];
        var videos;
    
        // Create a data binding for our ListView
    
        var videoResults = new WinJS.Binding.List();
    
        // Process the video feeds
    
        function getFeeds() {
    
            videos = [
            {
                key: "Bookmarks",
                url: 'xml url here',
                title: 'tbd', updated: 'tbd',
                backgroundImage: 'tbd',
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "History",
                url: 'xml url here',
                title: 'tbd', updated: 'tbd',
                backgroundImage: darkGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "Playlist",
                url: 'xml url here',
                title: 'tbd', updated: 'tbd',
                backgroundImage: darkGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "Browse",
                url: 'xml url here',
                title: 'tbd', updated: 'tbd',
                backgroundImage: darkGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "Popular",
                url: 'xml url here',
                title: 'tbd', updated: 'tbd',
                backgroundImage: darkGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            },
            {
                key: "New",
                url: 'xml url here',
                title: 'tbd', updated: 'tbd',
                backgroundImage: darkGray,
                acquireSyndication: acquireSyndication, dataPromise: null
            }];
    
            videos.forEach(function (feed) {
                feed.dataPromise = feed.acquireSyndication(feed.url);
                dataPromises.push(feed.dataPromise);
            });
    
    
            return WinJS.Promise.join(dataPromises).then(function () {
                return videos;
            });
        }
    
        function acquireSyndication(url) {
    
            return WinJS.xhr({ url: url });
        }
    
        function getvideoResults() {
            getFeeds().then(function () {
    
                videos.forEach(function (feed) {
                    feed.dataPromise.then(function (articlesResponse) {
                        var articleSyndication = articlesResponse.responseXML;
    
                        feed.title = feed.key;
    
                        //feed.backgroundImage = articleSyndication.selectSingleNode("//*[name()='media:thumbnail']").text;
                        getItemsFromXml(articleSyndication, videoResults, feed);
                    });
                });
            });
    
            return videoResults;
    
        }
    
        function getItemsFromXml(articleSyndication, videoResults, feed) {
            // Get the info for each video post
    
            var posts = articleSyndication.selectNodes("//item");
    
            var t = feed.key;
            var y = t;
            // Process each video post
            for (var postIndex = 0; postIndex < posts.length; postIndex++) {
                var post = posts[postIndex];
    
                var postTitle = post.selectSingleNode("title").text;
                var type = "";
    
    
                var image = $(post).find("media\\:thumbnail").last();
                var res = image.attr("url");
    
                videoResults.push({
                    group: feed,
                    classType: type,
                    key: feed.title,
                    title: postTitle,
                    date: postDate,
                    backgroundImage: res
                });
    
    
            }
    
        }
    
    
    
        // Organize the data for display
        function getGroupedData() {
    
    
            return videoResults.createGrouped(function (item) { return item.group.key; },
            function (item) { return item.group; },
            function (l, r) { return l < r; });
    
        }
    
        function getItemsFromGroup(group) {
            return list.createFiltered(function (item) { return item.group.key === group.key; });
        }
    
        var list = getvideoResults();
        var groupedItems = getGroupedData();
    
        WinJS.Namespace.define("data", {
            items: groupedItems,
            groups: groupedItems.groups,
            getItemsFromGroup: getItemsFromGroup
        });
    })();
    
    function groupInfo() {
        return {
            multiSize: true,
            slotWidth: 10,
            slotHeight: 10
        };

    Wednesday, May 16, 2012 5:13 PM
  • Just a quick observation here.  It looks to me like getVideoResults() has the potential of returning before the feeds have been processed because of the async process.  Also, shouldn't getFeeds().then(function () { have feed as the argument to the function?  

    By the way, you may have a runtime error that would not show up in the debug console unless you have enabled Debug > Exceptions > JavaScript Runtime


    • Edited by jrboddie Wednesday, May 16, 2012 6:14 PM
    Wednesday, May 16, 2012 6:13 PM
  • Ah, I enabled runtime exceptions and it threw this.. dont think this is related though? Googled it but not much on it. Is a resource map not something you add to the project like a plugin, player framework for smooth streaming for example.

    Wednesday, May 16, 2012 9:03 PM
  • Maybe I am misunderstanding your code but  getFeeds and getVideoResults have embedded asynchronous functions.  The makes them asynchronous as well. The problem is that you are not returning promises or calling them as asynchronous functions.  Which example are you using for your data.js?

    I think your two functions should each have a pattern that looks like this:

    function myAsync() {
            return new WinJS.Promise(function (complete) {
                //do stuff
                asyncSomeOtherFunc().then(function(){
                    //do stuff when asyncSomeOtherFunc has finished
                    //and produce a result
                    complete(result);  //send result back to the caller of myAsync
                });
            });
        }

    The thrown runtime error may or may not be related.

    Wednesday, May 16, 2012 10:12 PM
  • Hi jr,

    This is the example I'm following. You'll see I've changed very little and how the functions are structured.. am following it to spec.

    http://msdn.microsoft.com/en-us/library/windows/apps/br211385.aspx

    Thursday, May 17, 2012 8:53 AM
  • Solarpitch,

    I've studied your code against the sample and the template and can't see any deviation.  So, I'm stumped.  Sorry.

    Not sure if you can, but uncheck the proposed answer in this thread to get Jeff's attention again.  Your original click event handler seems to be right out of the template.

    So, are there any changes to the template other than in data.js?

    Update: The resource exception could refer to a problem the app is having in reading your feed.  Are the url's valid?  Double check the getItemsFromXml(). I suggest setting some breakpoints in data.js to check for expected results in the list.


    • Edited by jrboddie Thursday, May 17, 2012 12:49 PM
    Thursday, May 17, 2012 11:25 AM
  • Hi Solar,

    Can you send me an email from here?  http://blogs.msdn.com/jpsanders/contact.aspx.

    We can connect and you can send me your troubled project!

    -Jeff


    Jeff Sanders (MSFT)

    Thursday, May 17, 2012 1:13 PM
    Moderator