cmonti
cmonti

Reputation: 187

Set observable value with another observable

I have this model:

self.model {
   items: {
       Number: ko.observable(),
       Name: ko.observable(),
       NumberTwo: ko.computed(function () {
          return self.model.items.Number();
       })
   }
}

I need to initialize NumberTwo with the value on Number so I created a computed observable, but it gives me an error on the return line. Is anything wrong with this? Probably because I'm not referring the observable Number correctly?

Upvotes: 1

Views: 2391

Answers (2)

Jeroen
Jeroen

Reputation: 63699

As an alternative to @RoyJ's answer, I prefer using the Constructor Function pattern, which can feel similar to using classes in OO languages. For example:

var Items = function() {
  var self = this;
  self.number = ko.observable();
  self.name = ko.observable();
  self.numberTwo = ko.computed({
    read: function() {
      return self.number();
    },
    write: function(newValue) {
      console.log(newValue); // Or whatever
      self.number(newValue);
    }
  });
};

var Model = function() {
  var self = this;
  self.items = new Items();
};

var Root = function() {
  var self = this;
  self.model = new Model();
};

ko.applyBindings(new Root());

Naming convention wise, I advise using PascalCase for constructor functions, and camelCase for members and variables.

With this pattern, you're being more SOLID, having numberTwo encapsulated inside Items view models, and not having to refer two steps up the $parent tree to get to the sibling proeprty number.

Upvotes: 0

Roy J
Roy J

Reputation: 43881

It's because the computed is executed when you create it, at which time self.model is not populated. You can use the deferEvaluation option to make it wait until it is accessed, or you can create the computed after the model has been initialized. To use it, you have to specify your function as the read element of the parameter object.

NumberTwo: ko.computed({
  read: function () {
    return self.model.items.Number();
  },
  deferEvaluation: true
});

Update: If you want to add a write function to the computed, it could be

write: function (newValue) {
  self.model.items.Number(newValue);
}

But at this point, you've just made it an alias for Number, which would be better done like this:

self.model = {
   items: {
       Number: ko.observable(),
       Name: ko.observable()
   }
};

self.model.items.NumberTwo: self.model.items.Number;

Upvotes: 1

Related Questions