notifyPropertyChange behavior


#1

The EmberMap screencast on DDAU input events was a huge :bulb: :bulb: :bulb: moment for me.

However, I’m curious why this.notifyPropertyChange('key.path') doesn’t seem to work. It has to be this.get('key').notifyPropertyChange('path') (which means that key must be an Ember.Object).

Here’s a twiddle reproducing the issue.

Should this work? If not, why not?


#2

The episode was fantastic. They explained DDAU in a way that no blog post ever did.

notifyPropertyChange is actually a low level API on ember object. It isn’t a high level API like you would expect in say a computed property. Notification of change are core to KVO (Key-Value Observing) in Ember. Since the API is designed on a per object level there is no point in having dot-notation nesting.

To perform as you suggest your actually working on the wrong abstraction layer. You saying that your top level component knows more about your key's path then key does. The correct level for notifications would be the object that owns the properties not some consumer of that object.

At the abstraction level your at in the example provided your component is only responsible for it’s own properties; meaning to accomplish a KVO notification it would have to be this.notifyPropertyChange('key') since key is under its ownership. path however is the responsibility of the key object. It should know when and how to notify any KVO.

All these dependencies and nesting comes to a hierarchy where at the bottom is an observer and the top a scalar value. In the case of Ember the observer is in the Glimmer engine and should always be the very last thing in the chain (hence why using observers yourself in components is highly frowned upon). This observer will perform a this.get() which asks did my dependencies change? if so recalculate. Otherwise, return the save value as before. Each step in that hierarchy will in turn perform this.get() which asks did my dependencies change? This continues till all computed properties are resolved.

In the normal case of Ember development the difference between a changed dependency and a cached one is simply the use of this.set() which will internally call this.notifyPropertyChange().

In your example above there are two conclusions to draw from:

  1. Don’t worry about the lower level nesting. A this.notifyPropertyChange('key') is enough to mark key.path as dirty and trigger Glimmer to start the this.get() chain.
  2. If you wish to be more explicit you can make a component level property that aliases to the nested one: keyPath: reads('key.path') then this.notifyPropertyChange('keyPath').