Search code examples
javascriptwindows-8winjs

How to dynamically bind a WinJS list view within a repeater


I have a WinJS Repeater which is using a template. That template contains a WinJS list view. I can't seem to figure out how to use data-win-bind to set the inner list views itemDataSource.

My Repeater:

<section id="genreView" aria-label="Main content" role="main">
    <div id="genreWrapper">
        <div id="genreRows" data-win-control="WinJS.UI.Repeater"
             data-win-options="{template: select('#genreRowTemplate')}">
        </div>
    </div>
</section>

My Template which contains a List View:

<div id="genreRowTemplate" data-win-control="WinJS.Binding.Template">
    <div id="genreRow">
        <h2 class="genreTitle" data-win-bind="innerText: genreTitle"></h2>
        <div class="genreMovieListView"
                data-win-control="WinJS.UI.ListView"
                data-win-bind="itemDataSource : data"
                data-win-options="{ layout: { type: WinJS.UI.GridLayout },
            itemsDraggable: false,
            selectionMode: 'single',
            tapBehavior: 'none',
            swipeBehavior: 'none',
            itemsReorderable: false,
            itemTemplate: select('#genreMovieTemplate')}">
        </div>
    </div>
</div>

My List View's template:

<div id="genreMovieTemplate" data-win-control="WinJS.Binding.Template">
    <div class="genreMovieItem">
        <img style="width: 175px; height: 250px;" data-win-bind="alt: title; src: posterUrl" />
    </div>
</div>

The data for the repeater is similar to this (only it's a binding list):

var repeaterData = [{genreTitle: "titleA", data: new WinJS.Binding.List() },
{genreTitle: "titleB", data: new WinJS.Binding.List() }
{genreTitle: "titleC", data: new WinJS.Binding.List() }
{genreTitle: "titleD", data: new WinJS.Binding.List() }];

The data is created on the fly and each binding list is actually a lot more data so I can't get a good sample of real data.

What I DO get is a repeated control, repeated exactly the number of times as the records in my bound list. What I DON'T get is the binding list displayed. My inner binding list is not getting databound via the data-win-bind. I've tried a few things and I either get nothing or an error. Any help is appreciated. Thanks.

EDIT: I think the right way to bind would be data-win-bind="data-win-options.itemDataSource: data", but doing that throws the following confusing error: "JavaScript runtime error: WinJS.UI.Repeater.AsynchronousRender: Top level items must render synchronously".


Solution

  • I was able to solve my problem, but I don't think I went about it in the right way. I went ahead and set the data source for the repeater, which gives me my genreRows from above. This was always working, it was just the child dataSource I couldn't figure out how to get to. My solution... set it in code after it loads. Nothing fancy, just a solution that feels a bit hacky to me. Here's my code in case it helps someone else get past this problem.

     var titleList = $(".genreRow > .genreTitle");
        var genreLists = $(".genreRow > .genreMovieListView");
        for (var i = 0; i < genreLists.length; i++) {
            var title = titleList[i].innerText;
            var listControl = genreLists[i].winControl;
    
            tempData.forEach(function (element, i) {
                if (element.genreTitle == title)
                    listControl.itemDataSource = element.data.dataSource;
            });
        };
    

    Basically the above code assumes the title is unique (which it is). So it uses this as a key to traverse the data and set the itemDataSource that way.

    I won't mark this as the accepted answer just in case someone can point out how to do this "right".