Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template binding not working when source is null/undefined

Tags:

knockout.js

Can anyone explain me what is wrong with my view model or template in this example jsfiddle?

It doesn't work as expected. Basically the view model contains an object and that object is null. In the view, there is a template binding to this object. As this object is null, it shouldn't render the template. However, it does try to render the template and fails in my example. If job object is null then I don't want to render the template.

According to this article by Ryan, if a viewmodel contains a null object and there is a "template binding" for this object, it won't render the template.

Here is my view model:

var job = function(title) {
    this.jobTitle = ko.observable(title);
}

var ViewModel = function(first, last) {
    this.firstName = ko.observable(first);
    this.lastName = ko.observable(last);
    //this.job = ko.observable(new job("software developer"));
    this.job = ko.observable(null);

    this.fullName = ko.computed(function() {
        return this.firstName() + " " + this.lastName();
    }, this);
};

ko.applyBindings(new ViewModel("FirstName", "LastName")); 

And this is the view:

<div class='liveExample'>   
    <p>First name: <input data-bind='value: firstName' /></p> 
    <p>Last name: <input data-bind='value: lastName' /></p> 
    <p data-bind="template: { name: 'editorTmpl', data: job }"></p>
    <h2>Hello, <span data-bind='text: fullName'> </span>!</h2>  
</div>

<script id="editorTmpl" type="text/html">
    Job: <input data-bind='value: jobTitle' />
</script>
like image 490
Hitesh Avatar asked May 18 '14 09:05

Hitesh


2 Answers

The linked artifice was written almost 3 years ago. By the time the latest version of Knockout was around 1.2.1.

And in Knockout 1.2.1 your code is working fine: Demo using KO 1.2.1

However since then Knockout has changed a lot so it is not supporting this behavior anymore.

Nowadays you need to use the if option of the template binding

<p data-bind="template: { name: 'editorTmpl', if: job, data: job}"></p>

Demo JSFiddle.

Or the with (if) binding to achieve the same outcome:

<div class='liveExample'>   
    <p>First name: <input data-bind='value: firstName' /></p> 
    <p>Last name: <input data-bind='value: lastName' /></p> 
    <!-- ko with: job -->
        <p data-bind="template: { name: 'editorTmpl'}"></p>
    <!-- /ko -->
    <h2>Hello, <span data-bind='text: fullName'> </span>!</h2>  
</div>

Demo JSFiddle.

like image 104
nemesv Avatar answered Dec 01 '22 18:12

nemesv


You could surround your template binding with a div which uses the 'if' data-binding to the job observable:

<div data-bind="if: job">
    <p data-bind="template: { name: 'editorTmpl', data: job }"></p>
</div>

The editor template is hidden when job is null, and visible when not null.

EDIT:

A better solution is to pass the 'if' option to the template binding:

<p data-bind="template: { if: job, name: 'editorTmpl', data: job }"></p>
like image 37
mathewbergt Avatar answered Dec 01 '22 18:12

mathewbergt