mario595
mario595

Reputation: 3761

Text binding not working properly

I've got the following js:

var ViewModel = function() {
  var self = this;
  self.projects = ko.observableArray([]);
  self.currentProject = ko.observable();

  self.selectProject = function (project) {
    self.currentProject(project);
  };
}
var vm = new ViewModel();
ko.applyBindings(vm);



$(function() {
    $('#spinner-wrapper').show();
    $.getJSON("some/url", function(data){

        vm.projects(data.projects);
        vm.selectProject(data.projects[0]);
    });
});

And the following HTML:

<ul class="nav nav-pills nav-stacked" data-bind="foreach: {data:projects, as: 'project'}">
   <li><a href="#" data-bind="text:projectName, click: vm.selectProject"></a></li>
</ul>
<h1 data-bind="text:currentProject.projectName"></h1>

So everytime I click an <a>, the selectProject method get called, and self.currentProject changes properly. The problem I have is that h1 doesn't show anything.

Upvotes: 1

Views: 1602

Answers (1)

user3297291
user3297291

Reputation: 23372

Your currentProject property is observable. This means it's a function you'll have to call to get your actual property from it. The function doesn't have a property named pojectName, so it will return undefined (note that it won't throw an error).

If you can be sure currentProject always holds an object with a projectName property, you can easily fix your data-bind like so:

data-bind="currentProject().projectName"

(Find out how knockout gets and sets observables here)

However, in your view model, currentProject is initialized with value undefined. Here's some ways of dealing with the undefined value:

  1. Use a with binding (my personal preference)

A with binding doesn't render nor data-binds the HTML it encapsulates if its value isn't properly defined:

<h1 data-bind="with: currentProject">
  <span data-bind="text: projectName"></span>
</h1>

Drawbacks: you'll need an extra element or a virtual binding. Watch out that there aren't any weird flashes when elements are removed...


  1. Create a computed property in your viewmodel:

    self.currentProjectName = ko.pureComputed(function() {
      var currentProject = self.currentProject();
      return currentProject ? currentProject.projectName : "";
    });
    

Drawbacks: clutters your view model. Pros: easily create an empty state/placeholder


  1. Fix it in the data-bind:

    <h1 data-bind="text:currentProject() ? currentProject().projectName : ''"></h1>
    

This is basically the same approach as (2).

Drawbacks: clutters your view, prone to bugs.

Upvotes: 1

Related Questions