Reputation: 315
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:
Everything works well until I update the computed property v2 directly with "set", when I update v1 again, v2 is not reevaluated.
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
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
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