0

Am I missing anything, or is it simply not possible to declare a computed "inline" property like id_and_name below in my first example?

function viewmodel(){

    var self = this;

    // adding 'inline' won't work (exception that the functions doesn't exist):
    self.person = ko.observable({
        id: ko.observable(),
        name: ko.observable(),
        id_and_name: ko.computed(function(){ return this.id() + this.name(); }, self.person)
    });

    // this works:
    self.person.id_and_name = ko.computed(function(){ 
        return this.id() + this.name(); 
    }, self.person);
}
filur
  • 2,116
  • 6
  • 24
  • 47
  • What version of knockout are you using? You could try id_and_name: ko.pureComputed(function(){ return this.person.id() + this.person.name(); }, self) – Jonathan Feb 25 '16 at 23:11
  • @Jonathan I'm using the latest version. But as far as I can tell, this issue is more related to how javascript handles things, rather than knockout? But I will give it a try :) – filur Feb 26 '16 at 06:23

1 Answers1

1

Well, self.person is undefined until after the ko.observable call has returned. The computed is bootstrapped before that, so it is bootstrapped at a moment when self.person is still undefined. You can check it out in the computed source code file, pretty easy to read actually.

Here's one way to look at that:

function viewmodel() {
  var self = this;

  self.person = "temp";

  self.person = ko.observable({
    id: ko.observable(),
    name: ko.observable(),
    id_and_name: ko.computed(function() {
      console.log(this);
      return this.id() + this.name();
    }, self.person)
  });
}

It'll log "temp" upon initializing, because that's what self.person is at that time. You cannot change the this target for the computed read function after it was created.

So nope, what you want can't be done. You need your second solution or a proper view model constructor function*.


* Your top level viewmodel is already such a constructor function. You could create an inner constructor funciton person with id and name properties, and new that up, give it a id_and_name computed that will automatically have the correct this bound.

Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • Thank you. What about `ko.pureComputed` which is mentioned in the comments? – filur Feb 26 '16 at 06:22
  • Also, what do you mean by "proper" view model constructor function? This is the function in question, so can you please elaborate "proper"? :) – filur Feb 26 '16 at 06:28
  • I've added a footnote explaining my constructor function suggestion. (Also, `pureComputed` has no effect on this problem whatsoever, see (e.g.) [this](http://stackoverflow.com/a/30317890/419956)). – Jeroen Feb 26 '16 at 15:10
  • Gotcha, thanks again for all your help! Related question, is it valid to add an instance of a function to an observable, e.g. `self.person = ko.observable(new person())`? – filur Feb 26 '16 at 15:34
  • 1
    Most definitely. That's exactly how I'd do it. Have you checked out [the Knockout tutorials](http://learn.knockoutjs.com/) yet? They're short, to the point, and explain all this pretty well. – Jeroen Feb 26 '16 at 15:55
  • Yeah I've skimmed through them but obviously missed that part :) Thanks – filur Feb 27 '16 at 10:44