Answered by:
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 -
- Edited by S - Lee Whitney Sunday, March 4, 2012 6:34 PM
- Edited by Jeff SandersMicrosoft employee, Moderator Thursday, March 8, 2012 2:44 PM Better description
Sunday, March 4, 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)
- Marked as answer by Jeff SandersMicrosoft employee, Moderator Thursday, March 8, 2012 2:44 PM
Thursday, March 8, 2012 2:37 PMModerator
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 5, 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)
- Proposed as answer by Jeff SandersMicrosoft employee, Moderator Monday, March 5, 2012 8:31 PM
- Unproposed as answer by S - Lee Whitney Tuesday, March 6, 2012 1:23 AM
Monday, March 5, 2012 8:31 PMModerator -
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-
- Edited by S - Lee Whitney Tuesday, March 6, 2012 1:23 AM
Tuesday, March 6, 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 6, 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 6, 2012 8:59 PMModerator -
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)
- Proposed as answer by Jeff SandersMicrosoft employee, Moderator Wednesday, March 7, 2012 8:24 PM
Wednesday, March 7, 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
- Edited by Peter Kellner Wednesday, March 7, 2012 3:32 PM mis spelling
- Merged by Jeff SandersMicrosoft employee, Moderator Thursday, March 8, 2012 2:42 PM Same issue
Wednesday, March 7, 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 7, 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 7, 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 7, 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 7, 2012 8:25 PMModerator -
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 8, 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 8, 2012 1:02 PMModerator -
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)
- Marked as answer by Jeff SandersMicrosoft employee, Moderator Thursday, March 8, 2012 2:44 PM
Thursday, March 8, 2012 2:37 PMModerator -
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