g13013
g13013

Reputation: 315

Computed Property not updating after direct set

I think i am facing a bug regarding setting value directly to a computed property that seem to break computing when it's related keys changes again, here an example:

o = Ember.Object.extend({
    v1: null,
    v2: function (){
        console.log('evaluation of v2', arguments);
        return this.get('v1') + '!!!';
    }.property('v1'),
    v1_Observer: function () {
        console.warn('v1 changed:', this.get('v1'));
    }.observes('v1'),
    v2_Observer: function (){
        console.info('v2 changed:', this.get('v2'));
    }.observes('v2')
});

oi = o.create();
oi.set('v1', 'Value v1 one');
oi.set('v2', 'Value direct to v2');
oi.set('v1', 'Value v1 two');
Ember.assert('v2 should be "Value v1 two!!!"', oi.get('v2') === (oi.get('v1') + '!!!'));

I thinks there is 2 bugs here:

  1. Everything works well until I update the computed property v2 directly with "set", when I update v1 again, v2 is not reevaluated.

  2. when setting v2 directly its observer is called twice !

according to the documentation http://emberjs.com/guides/object-model/computed-properties/ we can directly set the value of a computed property with 'set' witch will be called with 2 parameters (key, value)! but in my tests, the property v2 only fires once, when v1 changed the first time.

this is the output of the console :

evaluation of v2 ["v2"]
v2 changed: Value v1 one!!!
v1 changed: Value v1 one
v2 changed: Value direct
v2 changed: Value direct
v1 changed: Value v1 two
Assertion failed: v2 should be "Value v1 two!!!"

Upvotes: 3

Views: 1948

Answers (2)

Darshan Sawardekar
Darshan Sawardekar

Reputation: 5075

Ember uses a runloop to optimize bindings and keep DOM updates to a minumum. It does this by putting property changes like these on a queue. The queue however is a little smarter.

If you were to say modify a property 10 times before it is rendered to the DOM, it will only use the last value you set for the property. As a result when you need to display the property in the DOM, it only needs to be updated once.

Further a computed property is a function that acts as both a getter and a setter depending on the number of arguments passed in. The syntax is,

myProperty: function(key, value) {
  if (value) {
    // setter
  } else {
    // getter
  }
}.property()

In the example above you are only returning the value computed from the dependent v1. You also need to provide a setter that puts backs the value into v1 from the v2 computed property.

Upvotes: 1

Gosha A
Gosha A

Reputation: 4570

Running your examples, I see the following in my console

> oi = o.create();

> oi.set('v1', 'Value v1 one');
[Log] evaluation of v2 ["v2"]
[Log] v2 changed: Value v1 one!!!
[Warning] v1 changed: Value v1 one

> oi.set('v2', 'Value direct to v2');
[Log] v2 changed: Value direct to v2

> oi.set('v1', 'Value v1 two');
[Log] v2 changed: Value direct to v2
[Warning] v1 changed: Value v1 two

List item when setting v2 directly its observer is called twice !

As you could've noticed, the observer of 'v2' is called twice in the row because you first set the value of v1, which makes v2 recompute and the observer fire, and it runs the second time when you set v2 directly — so there is nothing to wonder about.

List item Everything works well until I update the computed property v2 directly with "set", when I update v1 again, v2 is not reevaluated.

Once you set v2 manually, you basically tell computed property to go away and replace it with just a value (essentially, v2 was a function and you set it to a value). Why would it re-eval?

Upvotes: 1

Related Questions