Matt Sieker
Matt Sieker

Reputation: 9625

Templates not changing when template binding changes

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

Answers (1)

RP Niemeyer
RP Niemeyer

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

Related Questions