Jukka Dahlbom
Jukka Dahlbom

Reputation: 1740

Knockout.js failure to update previously null children

I am trying to do a fairly simple partial update. I update a view models' property "person", which is initially null, with an object with its own child property "lastName". This fails with "no method person.lastName()" when trying to notify subscribers.

Fiddle demonstrating the issue: http://jsfiddle.net/P4Jd3/4/

HTML

<body>
  <hr/>
  <div data-bind="text: rootdata"></div>
  <hr/>
  <div data-bind="if: person">
    <div data-bind="text: person.lastName()?person.lastName()+'###':'foo'">
    </div>
  </div>
  <hr/>
  <input type="submit" data-bind="click: updatedata" value="update data"></input>
</body>

JS:

newdata = {
    person: {
        lastName: "Mr.Bar"
    },
    rootdata : "Root 2"
}

model = {
    self: this,
    person : ko.observable(null),
    rootdata : ko.observable("Init root"),
    updatedata: function() {
        ko.mapping.fromJS(newdata, {}, model);
    }
}

ko.applyBindings(model);

At the moment of update, I get an error stating that Object function [ko observable junk string] has no method lastName().

Message: TypeError: Object function d(){if(0<arguments.length){if(!d.equalityComparer||!d.equalityComparer(c,arguments[0]))d.H(),c=arguments[0],d.G();return this}b.r.Wa(d);return c} has no method 'lastName';
Bindings value: text: person.lastName()?person.lastName()+'###':'foo' 

That person.lastName()+"##" is needed for combining property values with optional text formatting, depending on whether some properties are non-empty.

I am out of ideas on this one.

Upvotes: 0

Views: 114

Answers (3)

Michael Best
Michael Best

Reputation: 16688

This is a perfect use-case for the with binding. If you replace if: person with with: person, it simplifies your code and just works:

<div data-bind="with: person">
    <div data-bind="text: lastName() ? lastName()+'###' : 'foo'"></div>
</div>

http://jsfiddle.net/mbest/P4Jd3/5/

Upvotes: 2

ebram khalil
ebram khalil

Reputation: 8331

simply remove the () from lastName property. Because it's not observable property

OR edit your code to define new model for your data with observables properties

Upvotes: 0

Paul Manzotti
Paul Manzotti

Reputation: 5147

Your person object doesn't have a lastname property, let alone an observable when you call applyBindings. It is only created when you call upadteData.

I usually initialise my view model with blank observables:

model = {
    self: this,
    person : ko.observable({ lastName: ko.observable('')}),
    rootdata : ko.observable("Init root"),
    updatedata: function() {
        ko.mapping.fromJS(newdata, {}, model);
    }
}

ko.applyBindings(model);

Upvotes: 3

Related Questions