There is a bug in WinJS that makes programmatically creating templates impossible. That is, the following code will never work:
WinJS.UI.setOptions(el.winControl, {
itemTemplate: new WinJS.Binding.Template(itemTemplateEl)
});
This code is attempting (!) to set a winControl's itemTemplate
property to a new WinJS.Binding.Template
object. But, it internally calls the setRenderer
method shown below (ui.js
). Which has a horrible, horrible bug.
This means programmatically setting templates is impossible with WinJS. A more extensive example of how this might occur in a very natural app is in complete-repo.html
.
As mentioned, the buggy code is shown below in ui.js
. The specific line in question is
this.renderer = newRenderer.renderItem;
This exhibits a classic JavaScript mistake, which you see repeatedly in StackOverflow questions: not differentiating between methods and functions. In short, the WinJS team is treating newRenderer.renderItem
as a function, when in fact it is a method. By simply assigning it, as you would a function, you lose an important piece of context: the this
pointer for the method.
The fix is to properly extract the method as a method, using Function.prototype.bind
:
this.renderer = newRenderer.renderItem.bind(newRenderer);
Fixing this would introduce no compatibility issues. There is a code path that currently never works, so nobody can possibly be using it. This change would make it work.
A runtime patch to fix this behavior is shown in fix.js
. As with all such runtime patches, the process is fragile.
Such a fundamental mistake in JavaScript semantics (the difference between methods and functions) does not inspire confidence. And the fact that it's in such a basic piece of the WinJS library (templating!) makes me concerned about the test coverage of the library in general.
This makes me fear that Microsoft does not expect us to write "real" WinJS apps, but only small, single-page samples that wouldn't need the flexibility provided by e.g. programmatic template binding.
Josh from the WinJS team here. I'll admit that it is a little odd that you can't use a template in this fashion. The intention was that people would be binding to the template HTML element in the DOM (e.g. when you say data-win-options="{ itemTemplate: myTemplate }") and in that case it works out because we put a function on the Template's element which implements the renderItem contract.
In this case you can work around this by saying:
new WinJS.UI.ListView(element, { itemTemplate: new WinJS.Binding>Template(templateDiv).element });
-josh