locked
how to limit items count in groups? (ContosoCookbook js)

    Question

  • hi,

    I am customizing the Contosocookbook (html / js) app sample.

    And I want to limit item counts of each group to '20' in the groupeditem page.  

    (ex - group1 : 20 items / group2 : 20 items / group3 : 20 items.. )

    How can i do that? Plese answer me..

    attachment : <data.js> in the js folder

    (function () {
        "use strict";
        function getItemReference(item) {
            return [item.group.key, item.title];
        }
        function resolveGroupReference(key) {
            for (var i = 0; i < groupedItems.groups.length; i++) {
                if (groupedItems.groups.getAt(i).key === key) {
                    return groupedItems.groups.getAt(i);
                }
            }
        }
        function resolveItemReference(reference) {
            for (var i = 0; i < groupedItems.length; i++) {
                var item = groupedItems.getAt(i);
                if (item.group.key === reference[0] && item.title === reference[1]) {
                    return item;
                }
            }
        }
        // This function returns a WinJS.Binding.List containing only the items
        // that belong to the provided group.
        function getItemsFromGroup(group) {
            return list.createFiltered(function (item) { return item.group.key === group.key; });
        }
        var list = new WinJS.Binding.List();
        var groupedItems = list.createGrouped(
            function groupKeySelector(item) { return item.group.key; },
            function groupDataSelector(item) { return item.group; }
        );
        // TODO: Replace the data with your real data.
        // You can add data from asynchronous sources whenever it becomes available.s
        // To load recipe data from Azure, change "data/Recipes.txt" to
        // "http://contosorecipes8.blob.core.windows.net/AzureRecipesRP".
        WinJS.xhr({ url: "/data/Recipes.txt" }).then(function (xhr) {
           var items = JSON.parse(xhr.responseText);
            // Add the items to the WinJS.Binding.List
            items.forEach(function (item) {
                list.push(item);
            });
        });
        WinJS.Namespace.define("Data", {
            items: groupedItems,
            groups: groupedItems.groups,
            getItemsFromGroup: getItemsFromGroup,
            getItemReference: getItemReference,
            resolveGroupReference: resolveGroupReference,
            resolveItemReference: resolveItemReference
        });
    })();

    attachment : <groupedItems.js> in the groupedItems folder

    (function () {
        "use strict";
        var appView = Windows.UI.ViewManagement.ApplicationView;
        var appViewState = Windows.UI.ViewManagement.ApplicationViewState;
        var nav = WinJS.Navigation;
        var ui = WinJS.UI;
        ui.Pages.define("/pages/groupedItems/groupedItems.html", {
            // Navigates to the groupHeaderPage. Called from the groupHeaders,
            // keyboard shortcut and iteminvoked.
            navigateToGroup: function (key) {
                nav.navigate("/pages/groupDetail/groupDetail.html", { groupKey: key });
            },
            // 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) {
                var listView = element.querySelector(".groupeditemslist").winControl;
                listView.groupHeaderTemplate = element.querySelector(".headertemplate");
                listView.itemTemplate = element.querySelector(".itemtemplate");
                listView.oniteminvoked = this._itemInvoked.bind(this);
                // Set up a keyboard shortcut (ctrl + alt + g) to navigate to the
                // current group when not in snapped mode.
                listView.addEventListener("keydown", function (e) {
                    if (appView.value !== appViewState.snapped && e.ctrlKey && e.keyCode === WinJS.Utilities.Key.g && e.altKey) {
                        var data = listView.itemDataSource.list.getAt(listView.currentItem.index);
                        this.navigateToGroup(data.group.key);
                        e.preventDefault();
                        e.stopImmediatePropagation();
                    }
                }.bind(this), true);
                this._initializeLayout(listView, appView.value);
                listView.element.focus();
            },
            // This function updates the page layout in response to viewState changes.
            updateLayout: function (element, viewState, lastViewState) {
                /// <param name="element" domElement="true" />
                var listView = element.querySelector(".groupeditemslist").winControl;
                if (lastViewState !== viewState) {
                    if (lastViewState === appViewState.snapped || viewState === appViewState.snapped) {
                        var handler = function (e) {
                            listView.removeEventListener("contentanimating", handler, false);
                            e.preventDefault();
                        }
                        listView.addEventListener("contentanimating", handler, false);
                        this._initializeLayout(listView, viewState);
                    }
                }
            },
            // This function updates the ListView with new layouts
            _initializeLayout: function (listView, viewState) {
                /// <param name="listView" value="WinJS.UI.ListView.prototype" />
                if (viewState === appViewState.snapped) {
                    listView.itemDataSource = Data.groups.dataSource;
                    listView.groupDataSource = null;
                    listView.layout = new ui.ListLayout();
                } else {
                    listView.itemDataSource = Data.items.dataSource;
                    listView.groupDataSource = Data.groups.dataSource;
                    listView.layout = new ui.GridLayout({ groupHeaderPosition: "top" });
                }
            },
            _itemInvoked: function (args) {
                if (appView.value === appViewState.snapped) {
                    // If the page is snapped, the user invoked a group.
                    var group = Data.groups.getAt(args.detail.itemIndex);
                    this.navigateToGroup(group.key);
                } else {
                    // If the page is not snapped, the user invoked an item.
                    var item = Data.items.getAt(args.detail.itemIndex);
                    nav.navigate("/pages/itemDetail/itemDetail.html", { item: Data.getItemReference(item) });
                }
            }
        });
    })();

    thank you for reading.


    • Edited by 박대웅 Monday, January 7, 2013 4:12 PM
    Monday, January 7, 2013 4:03 PM

Answers

  • Thanks for your reply.

    Here is the basic idea of the code provided in that thread:

    The WinJS.Binding.List support some method for you to perform filtering, sorting or grouping on the items within the list. And you can use the "createFiltered" method to create a new List object which contains a sub set of the original List (and assign it to ListView or other controls as dataSource).


    #List.createFiltered method (Windows)
    http://msdn.microsoft.com/en-us/library/windows/apps/hh700741.aspx

    #Binding list and its projections
    http://fknet.wordpress.com/2012/06/10/binding-list-and-its-projections/


    Now, let's switch to the code used in that thread:

    var data = [
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "fifth", value: 5 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
    ];
    var list = new WinJS.Binding.List(data);
    var groupCount = {};
    var maxItems = 3;
    var filteredList = list.createFiltered(function _filterItems(item) {
        groupCount[item.group] = groupCount[item.group] ? groupCount[item.group] + 1 : 1;
        return groupCount[item.group] <= maxItems;
    });

    it just use "createFiltered" method to generate a filteredList which contains no more than 3 items for each group (based on its "group" property). How does this "3 items" limit work? Well, you can see that it defines a "groupCount={}" variable before invoking the "createFiltered" method. This "groupCount" variable is used as a hashtable which record the current number of items (for each group) be added into the filteredList. And in the delegate function supplied to the "createFiltered" method, it will increase the count (for the certain group) if a new item is added (approve to be added into the filtered list). If the item count of a certain group already reach the "maxItems" limit, the item will no longer be added into the filtered list.

    You can also use Visual studio debugger to set breakpoint and go through the code step by step (and watch the variables in function) so as to understand how it works. Hope this helps some.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by 박대웅 Thursday, January 10, 2013 9:23 PM
    Wednesday, January 9, 2013 2:23 AM
    Moderator

All replies

  • Hi,

    In case you want to limit the number of items be displayed in each group (by ListView control), you can define a filter function to restrict the number of items (for each group key) at data source (WinJS.Binding.List) level. The Listview control doesn't have such setting at UI level.

    Here is a former forum thread discussing on this


    #Limit the Items shown by listView?
    http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/fb428a26-4725-485e-94d2-ba556615fa77


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.


    Tuesday, January 8, 2013 2:29 AM
    Moderator
  • Thank you very much for your advice.

    I read the url.

    But I don't know how use that code. so sorry. I'm a beginner...

    So plese, would you expain more detail?

    How can use that code?

    var data = [
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "fifth", value: 5 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
    ];
    var list = new WinJS.Binding.List(data);
    var groupCount = {};
    var maxItems = 3;
    var filteredList = list.createFiltered(function _filterItems(item) {
        groupCount[item.group] = groupCount[item.group] ? groupCount[item.group] + 1 : 1;
        return groupCount[item.group] <= maxItems;
    });

    Tuesday, January 8, 2013 12:09 PM
  • Hi. I am customizing the ContosoCookbook (html/js) sample app.

    yesteryday, I asked how to limit item counts in each group of 'groupedItems' page,

    and some very nice and kind guy told me to use a below code..

    But I am a beginner (sorry!), I don't know how to use this code.

    Could you explain plese in more detail about where, what I have to change?

    thank you for reading..

    var data = [
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "fifth", value: 5 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
    ];
    var list = new WinJS.Binding.List(data);
    var groupCount = {};
    var maxItems = 3;
    var filteredList = list.createFiltered(function _filterItems(item) {
        groupCount[item.group] = groupCount[item.group] ? groupCount[item.group] + 1 : 1;
        return groupCount[item.group] <= maxItems;
    });


    • Edited by 박대웅 Tuesday, January 8, 2013 8:36 PM
    • Merged by Song Tian Wednesday, January 9, 2013 6:22 AM same question
    Tuesday, January 8, 2013 8:33 PM
  • Thanks for your reply.

    Here is the basic idea of the code provided in that thread:

    The WinJS.Binding.List support some method for you to perform filtering, sorting or grouping on the items within the list. And you can use the "createFiltered" method to create a new List object which contains a sub set of the original List (and assign it to ListView or other controls as dataSource).


    #List.createFiltered method (Windows)
    http://msdn.microsoft.com/en-us/library/windows/apps/hh700741.aspx

    #Binding list and its projections
    http://fknet.wordpress.com/2012/06/10/binding-list-and-its-projections/


    Now, let's switch to the code used in that thread:

    var data = [
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
        { group: "second", value: 2 },
        { group: "third", value: 3 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "fifth", value: 5 },
        { group: "forth", value: 4 },
        { group: "fifth", value: 5 },
        { group: "first", value: 1 },
    ];
    var list = new WinJS.Binding.List(data);
    var groupCount = {};
    var maxItems = 3;
    var filteredList = list.createFiltered(function _filterItems(item) {
        groupCount[item.group] = groupCount[item.group] ? groupCount[item.group] + 1 : 1;
        return groupCount[item.group] <= maxItems;
    });

    it just use "createFiltered" method to generate a filteredList which contains no more than 3 items for each group (based on its "group" property). How does this "3 items" limit work? Well, you can see that it defines a "groupCount={}" variable before invoking the "createFiltered" method. This "groupCount" variable is used as a hashtable which record the current number of items (for each group) be added into the filteredList. And in the delegate function supplied to the "createFiltered" method, it will increase the count (for the certain group) if a new item is added (approve to be added into the filtered list). If the item count of a certain group already reach the "maxItems" limit, the item will no longer be added into the filtered list.

    You can also use Visual studio debugger to set breakpoint and go through the code step by step (and watch the variables in function) so as to understand how it works. Hope this helps some.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by 박대웅 Thursday, January 10, 2013 9:23 PM
    Wednesday, January 9, 2013 2:23 AM
    Moderator