none
Display issue binding to itemTemplate in a fragment

    Question

  • When I try to bind a ListView to a template using WinJS.UI.ListLayout, it only displays raw JSON in the ListView.

    It seems it does not work when the code below is part of a fragment.

    So to duplicate just create a new project in VS11, which will use fragments (subpages), and the template will not render.

    <div id="regularListIconTextTemplate" data-win-control="WinJS.Binding.Template" >                        
                    <h4 data-win-bind="innerText: title"></h4>
                    <h6 data-win-bind="innerText: text"></h6>
                </div>
                        
                <div id="listView1" 
                    data-win-control="WinJS.UI.ListView" 
                    data-win-options="{ itemDataSource: myData.dataSource, itemTemplate: regularListIconTextTemplate, layout: { type: WinJS.UI.ListLayout } }"></div>  

    The data used is from the sdk sample:

    var myData = new WinJS.Binding.List([
                    { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", rating: 3 },
                    { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", rating: 3 },
                    { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", rating: 3 },
                    { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", rating: 3 },
                    { title: "Banana Blast", text: "Low-fat frozen yogurt", picture: "images/60Banana.png", rating: 3 }
                ]);

    Thanks -





    Sunday, March 04, 2012 5:59 PM

Answers

  • Got it,

    in your data-win-options declaration you can simply add a select statement for your template for the id (#) or class(.) depending on which you are using:

    itemTemplate: select('#myTemplateID')

    or

    itemTemplate: select('.myTemplateClass')

    This is due to the fact that the select will walk the DOM to find these at the time of the resolution of these properties.  You should only need to do this if your template and list view are in a fragment.

    -Jeff


    Jeff Sanders (MSFT)

    Thursday, March 08, 2012 2:37 PM

All replies

  • Wondering if you have what I see...if you set your ListView to GridLayout does it come out fine? Not what you need of course, but are the templates rendered?
    Monday, March 05, 2012 7:14 PM
  • See the walktrough for the ListView:

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

    WinJS.Binding.Template must have a single root element. Create a div element to serve as a parent for the template's contents.

    That should get you going!

    -Jeff


    Jeff Sanders (MSFT)

    Monday, March 05, 2012 8:31 PM
  • That was helpful to know but did not fix the problem.

    It still does not work in a subpage (fragment), but works fine when the template is in the main page (default.html):

    <div id="regularListIconTextTemplate" data-win-control="WinJS.Binding.Template" style="display: none">
        <div style="width: 150px; height: 100px;">
            <h4 data-win-bind="innerText: account"></h4>
            <h6 data-win-bind="innerText: region"></h6>
        </div>                        
    </div>

    Again to duplicate the problem, you just create a new project in VS11 beta and add in this template into the .html page that is loaded into default.html at startup.  

    Any help appreciated-



    Tuesday, March 06, 2012 1:22 AM
  • hi harlequin,

    i think i noticed what you are referring to in another situation, but in this specific case the template does not render with GridLayout nor ListLayout.

    The data is displayed in raw JSON format, rather than the rendered template format.

    Tuesday, March 06, 2012 1:26 AM
  • I will try and take some time to build a repro of this tomorrow.  Can you post what you see?

    Jeff Sanders (MSFT)

    Tuesday, March 06, 2012 8:59 PM
  • Hi,

    I have the same problem but I fix it temporary using a function as itemTemplate.

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

    In HTML markup I only declare itemDatasource property in the listView element:

    <div data-win-control="WinJS.UI.ListView" id="myListView" data-win-options="{layout: {type: WinJS.UI.ListLayout}, itemDataSource:ApplicationData.listViewData.dataSource}">
    </div>
    
    <div data-win-control="WinJS.Binding.Template" id="myItemTemplate">
          <div class="row">
                  <div data-win-bind="innerText:field1"></div>
                        <div data-win-bind="innerText:field2"></div>
                        <div data-win-bind="innerText:field3"></div>
                    </div>
           </div>
    </div>

    ... In my fragment ready function I write this code ...

    var listViewControl = myListView.winControl;
    listViewControl.itemTemplate = itemTemplateFunction;

    .. and this is my itemTemplateFunction...

        function itemTemplateFunction(itemPromise) {
    
            return itemPromise.then(function (item) {
                
                var template = myItemTemplate.winControl;
                var data = template.render(item.data);
                return data;
            });
        };

    it works!!!

    Anyway, i would like to know why template mechanism doesn't work in a Page Control Fragment.

    Cesar Cruz  (ilitia Technologies)


    Wednesday, March 07, 2012 9:38 AM
  • I've taken the default navigation app (consumer preview) and tried to add a simple listview.   The data shows, but it displays in raw json rather than formatted from the template.  I've put the static data in default.js so it gets loaded right away, then in homePage.html I've put the template. 

    Below are the files

    // default.js
    // http://go.microsoft.com/fwlink/?LinkId=232506
    (function () {
        "use strict";
        
        var dataArray = [
                { title: "Basic banana", text: "Low-fat frozen yogurt", picture: "images/60banana.png" },
                { title: "Banana blast", text: "Ice cream", picture: "images/60banana.png" },
                { title: "Brilliant banana", text: "Frozen custard", picture: "images/60banana.png" },
                { title: "Orange surprise", text: "Sherbet", picture: "images/60orange.png" },
                { title: "Original orange", text: "Sherbet", picture: "images/60orange.png" },
                { title: "Vanilla", text: "Ice cream", picture: "images/60vanilla.png" },
                { title: "Very vanilla", text: "Frozen custard", picture: "images/60vanilla.png" },
                { title: "Marvelous mint", text: "Gelato", picture: "images/60mint.png" },
                { title: "Succulent strawberry", text: "Sorbet", picture: "images/60strawberry.png" }
        ];
    
        var dataList = new WinJS.Binding.List(dataArray);
    
        // Create a namespace to make the data publicly
        // accessible.
        var publicMembers =
                {
                    itemList: dataList
                };
        WinJS.Namespace.define("DataExample", publicMembers);
    
        var app = WinJS.Application;
    
        app.onactivated = function (eventObject) {
            if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
                if (eventObject.detail.previousExecutionState !== Windows.ApplicationModel.Activation.ApplicationExecutionState.terminated) {
                    // TODO: This application has been newly launched. Initialize 
                    // your application here.
                } else {
                    // TODO: This application has been reactivated from suspension. 
                    // Restore application state here.
                }
                WinJS.UI.processAll();
            }
        };
    
        app.oncheckpoint = function (eventObject) {
            // TODO: This application is about to be suspended. Save any state
            // that needs to persist across suspensions here. You might use the 
            // WinJS.Application.sessionState object, which is automatically
            // saved and restored across suspension. If you need to complete an
            // asynchronous operation before your application is suspended, call
            // eventObject.setPromise(). 
        };
    
        app.start();
    })();

    homepage.html:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>homePage</title>
        <!-- WinJS references -->
        <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet">
        <script src="//Microsoft.WinJS.0.6/js/base.js"></script>
        <script src="//Microsoft.WinJS.0.6/js/ui.js"></script>
        <link href="/css/default.css" rel="stylesheet">
        <link href="/css/homePage.css" rel="stylesheet">
        <script src="/js/homePage.js"></script>
    </head>
    <body>
        <!-- The content that will be loaded and displayed. -->
        <div class="fragment homepage">
            <header aria-label="Header content" role="banner">
                <button class="win-backbutton" aria-label="Back" disabled></button>
                <h1 class="titlearea win-type-ellipsis"><span class="pagetitle">Welcome to Application1!
                    </span></h1>
            </header>
            <section aria-label="Main content" role="main">
                <div id="mediumListIconTextTemplate" data-win-control="WinJS.Binding.Template">
                    <div style="width: 150px; height: 100px;">
                        <div>
                            <!-- Displays the "title" field. -->
                            <h4 data-win-bind="innerText: title"></h4>
                            <!-- Displays the "text" field. -->
                            <h6 data-win-bind="innerText: text"></h6>
                        </div>
                    </div>
                </div>
                <div id="basicListView" data-win-control="WinJS.UI.ListView" data-win-options="{itemDataSource : DataExample.itemList.dataSource, itemTemplate: mediumListIconTextTemplate}">
                </div>
            </section>
        </div>
    </body>
    </html>


    Peter Kellner http://peterkellner.net Microsoft MVP • ASPInsider


    Wednesday, March 07, 2012 3:31 PM
  • Hi Peter,

    Can you try changing your options attribute slightly to read

    itemTemplate: select('#mediumListIconTextTemplate')

    instead of just the bare identifier? I believe the trouble is when processAll is being called, the fragment hasn't been parented to the DOM yet, and so the DOM id hasn't been promoted to a global.

    Cheers,

    -Jeff

    Wednesday, March 07, 2012 7:08 PM
  • If that doesn't work you can add this to homePage.js:

    // This function is called whenever a user navigates to this page. It
    // populates the page elements with the app's data.
    function ready(element, options) {
        WinJS.UI.processAll(element).then(function elementsProcessed() {
            var lv = document.getElementById("basicListView").winControl;
            lv.itemTemplate = document.getElementById("mediumListIconTextTemplate");
        });
    }

    Senior Dev for Windows Phone Services

    Wednesday, March 07, 2012 7:43 PM
  • I'm doing a presentation tonight on win8 metro (meetup) and have it somewhat figured out but not enough detail to really post. The code I had to add looks something like this.  I think it has to do with the bind missing

     ui.setOptions(listView, {
                //itemTemplate: element.querySelector("#legislaturesTemplate"),
                itemDataSource: DataExampleLeg.itemList.dataSource,
                oniteminvoked: this.itemInvoked.bind(this)
            });


    Peter Kellner http://peterkellner.net Microsoft MVP • ASPInsider

    Wednesday, March 07, 2012 7:50 PM
  • Is your datasource visible in the global namespace or is it inside of a namepace and hidden?


    Jeff Sanders (MSFT)

    Wednesday, March 07, 2012 8:25 PM
  • My datasource is created inside an anonymous function but I create a namespace called "ApplicationData" to make the data publicily accessible, so my datasource its inside of a namespace and public.

    The question is... can it affect to the problem? The JSON representation of the datasource is visible in the listview so the datasource is accessible outside.

    Thursday, March 08, 2012 12:36 PM
  • As long as it is visible you should be OK.  I will try and build a repro of this.


    Jeff Sanders (MSFT)

    Thursday, March 08, 2012 1:02 PM
  • Got it,

    in your data-win-options declaration you can simply add a select statement for your template for the id (#) or class(.) depending on which you are using:

    itemTemplate: select('#myTemplateID')

    or

    itemTemplate: select('.myTemplateClass')

    This is due to the fact that the select will walk the DOM to find these at the time of the resolution of these properties.  You should only need to do this if your template and list view are in a fragment.

    -Jeff


    Jeff Sanders (MSFT)

    Thursday, March 08, 2012 2:37 PM
  • Wow, don't I think I could have guessed that in a 100 years, but hey, that's life in a beta right? :)

    It's now working well, thanks for your help Jeff -

    Lee

    Saturday, March 10, 2012 2:23 PM