Reputation: 9625
I've got a page where I want to change which template is used to display a list of items (for example a simple vs an advanced view). Sample code:
<script type="text/html" id="template1">
Template 1
</script>
<script type="text/html" id="template2">
Template 2
</script>
<input type="checkbox" data-bind="checked: viewSelect"/>
<button data-bind="click: newArray">Refresh Array</button>
<ul data-bind="template:{name: templateBinding, foreach: items}">
</ul>
JS:
var ViewModel = function(){
var self = this;
this.viewSelect = ko.observable();
this.newArray = function(){
console.log("newArray");
self.items([{text:"Item1"},{text:"Item2"},{text:"Item3"}]);
};
this.templateBinding = ko.computed(function(){
console.log("templateBinding");
if(self.viewSelect()){
return "template1";
} else{
return "template2";
}
});
this.items = ko.observableArray([{text:"Item1"},{text:"Item2"},{text:"Item3"}]);
};
ko.applyBindings(new ViewModel());
I've created a fiddle with this code.
Here's what's happening: I'm expecting Knockout to re-create the displayed list when the template changes. The computed
hooked to templateBinding
is called (this can be confirmed from the console), but the template does not change, toggling the checkbox does not change the display. However, changes to the contents of the array does refresh the list, with the new template.
Is there an elegant way of doing this, or am I doing something wrong?
Upvotes: 0
Views: 94
Reputation: 114792
When using a dynamic template name for items in a foreach, you will need to specify a function to execute. This will be called for each item (and will pass the item as the first arg).
So, you could change your current code to:
this.getTemplate = function(){
if(self.viewSelect()){
return "template1";
} else{
return "template2";
}
};
and bind like:
<ul data-bind="template:{name: getTemplate, foreach: items}">
Here is an updated fiddle: http://jsfiddle.net/rniemeyer/qAEXh/
Upvotes: 2