locked
How to limit a listview (datasource) to have only 9 items RRS feed

  • Question

  • I would like to limit the amount of items the LV shows to only the 9 most recent documents (coming from a DB Query).

    These items could change at any time (as new items are fed into the app or deleted from it). How should the datasource behave to have only 9 items and the LV to react on changes to these items with nice animated LV transitions?

    Monday, September 10, 2012 3:21 PM

Answers

  • You can create a filtered projection of your DataSource with any logic you choose (in your case, just increment an integer and only let the first 9 through and remove the rest):

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

    Here's an example I wrote that limits the number of items we display in any arbitrary group:

    http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/fb428a26-4725-485e-94d2-ba556615fa77

    My filtering function is probably a little opaque, but the idea is that your predicate function gets run against every item in the list, and it should return true if you want that item to appear in the filtered list, obviously returning false means that the item is not included in the filtered list.

    As I said before, this "createdFiltered" function is a projection of the underlying datasource, so if that changes then the filtered datasource will change too.

    • Proposed as answer by Bryan Thomas Monday, September 10, 2012 4:44 PM
    • Marked as answer by Dino He Monday, September 24, 2012 4:28 AM
    Monday, September 10, 2012 4:44 PM
  • I hadn't tested it with a dynamic list, and I can see how the groupCount would never change (and thus the filtered list would get cleared). Here's a work-around that clears the count by listening to the listview's change events.

    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 _groupCount = 0;
        var _maxItems = 10;
        var _listView;
    
        app.onready = function pageLoaded() {
            _listView = document.getElementById("myList").winControl;
    
            var list = new WinJS.Binding.List(_data);
            var filteredList = list.createFiltered(function _filterItems(item) {
                return ++_groupCount <= _maxItems;
            });
    
            _listView.addEventListener("loadingstatechanged", listViewReady);
    
            WinJS.UI.setOptions(_listView, {
                layout: new WinJS.UI.GridLayout(),
                itemTemplate: document.getElementById("itemTemplate")
            });
    
            _listView.itemDataSource = filteredList.dataSource;
    
            // Randomly change the unfiltered set every second.
            setInterval(function () {
                var i = Math.floor(10 * Math.random())
                var item = list.getAt(i);
                item.value++;
                list.setAt(i, item);
            }, 1000);
        };
    
        function listViewReady(eventInfo) {
            if ( _listView && _listView._loadingState == "complete") {
                // listView is done loading items, reset the counters.
                _groupCount = 0;
            }
        };

    • Marked as answer by Dino He Monday, September 24, 2012 4:28 AM
    Monday, September 10, 2012 6:51 PM

All replies

  • You can create a filtered projection of your DataSource with any logic you choose (in your case, just increment an integer and only let the first 9 through and remove the rest):

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

    Here's an example I wrote that limits the number of items we display in any arbitrary group:

    http://social.msdn.microsoft.com/Forums/en-US/winappswithhtml5/thread/fb428a26-4725-485e-94d2-ba556615fa77

    My filtering function is probably a little opaque, but the idea is that your predicate function gets run against every item in the list, and it should return true if you want that item to appear in the filtered list, obviously returning false means that the item is not included in the filtered list.

    As I said before, this "createdFiltered" function is a projection of the underlying datasource, so if that changes then the filtered datasource will change too.

    • Proposed as answer by Bryan Thomas Monday, September 10, 2012 4:44 PM
    • Marked as answer by Dino He Monday, September 24, 2012 4:28 AM
    Monday, September 10, 2012 4:44 PM
  • thanks Bryan! Your referenced code, does it work with dynamic changing lists too? Cause the counter for each group is never reset. So if I change the underlying list (that filtered list is a projection of), the filter function is called again. But there are already 3 items in the "groupCount" array.
    Monday, September 10, 2012 6:09 PM
  • I hadn't tested it with a dynamic list, and I can see how the groupCount would never change (and thus the filtered list would get cleared). Here's a work-around that clears the count by listening to the listview's change events.

    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 _groupCount = 0;
        var _maxItems = 10;
        var _listView;
    
        app.onready = function pageLoaded() {
            _listView = document.getElementById("myList").winControl;
    
            var list = new WinJS.Binding.List(_data);
            var filteredList = list.createFiltered(function _filterItems(item) {
                return ++_groupCount <= _maxItems;
            });
    
            _listView.addEventListener("loadingstatechanged", listViewReady);
    
            WinJS.UI.setOptions(_listView, {
                layout: new WinJS.UI.GridLayout(),
                itemTemplate: document.getElementById("itemTemplate")
            });
    
            _listView.itemDataSource = filteredList.dataSource;
    
            // Randomly change the unfiltered set every second.
            setInterval(function () {
                var i = Math.floor(10 * Math.random())
                var item = list.getAt(i);
                item.value++;
                list.setAt(i, item);
            }, 1000);
        };
    
        function listViewReady(eventInfo) {
            if ( _listView && _listView._loadingState == "complete") {
                // listView is done loading items, reset the counters.
                _groupCount = 0;
            }
        };

    • Marked as answer by Dino He Monday, September 24, 2012 4:28 AM
    Monday, September 10, 2012 6:51 PM