2

Please see below sample code. Given I have a component my-text-box

my-text-box.hbs

{{my-text-box value=modelName}}

I want to observe the changes of value property via didReceiveAttrs hook instead of observers for better performance.

my-text-box.js

didReceiveAttrs: function(args) {
    if (args.oldAttrs == null) {
        // This is the initial render, but I don't need to anything here.
    } else if (args.newAttrs.value != args.oldAttrs.value) {
        // supposed `value` was changed from outside, I can do something here...

        // BUT, `args.newAttrs.value` is not always the prop value, 
        // `Ember` would automatically wrap it with `{{mut}}` helper. 
        // The data structure would be: 
        // {
        //    value: value,
        //    update: function (val) {
        //        source.setValue(val);
        //    }
        // }
    }
}

What I want is that I don't have to care whether the attr value is a mutable cell or not, I should get a way that always get the real value. I see there is a HTMLBars hook ember-htmlbars/hooks/get-value but it's not exposed to public API. And what I'm thinking is that maybe Ember should change both newAttrs and oldAttrs to have direct values instead of those mutable objects.

Does anybody have a way to handle that? Thanks!

shijistar
  • 111
  • 4
  • `newAttrs` and `oldAttrs` aren't public API either :X – locks Dec 07 '16 at 02:28
  • so it's hard to replace `observers`, I need to know whether one property is changed or not. http://emberjs.com/api/classes/Ember.Component.html#event_didReceiveAttrs – shijistar Dec 09 '16 at 11:01

2 Answers2

1

My suggestion is to store the previous value yourself, and then compare:

export default Ember.Component.extend({
  _previousAttr: null,

  didReceiveAttrs() {
    this._super(...arguments);
    if (this.get('_previousAttr') !== this.get('attrName')) {
      this.set('_previousAttr', this.get('attrName'));
      // do your thing
    }
  }
});
Ember Freak
  • 12,918
  • 4
  • 24
  • 54
locks
  • 6,537
  • 32
  • 39
  • Thank you for your suggestion. It makes sense to me, I'm doing like this too. But I have to make a `shadow` for all properties I need to watch, it's lot of extra works. Much better if Ember extracts the `new` values and `old` values, I can easily compare them, without any extra cost. Hope Ember maintainers can see this, and consider it. – shijistar Dec 09 '16 at 11:06
  • Did you get any solution? I am having the same issue. Please help to resolve mine! – Shreya Shah Apr 19 '19 at 18:25
1

Ember component lifecycle hook args are deprecated according to RFC #191.

So it would be better to do thing like this:

Ember.Component.extend({
  didReceiveAttrs() {
    let oldAttrs = this.get('_previousAttrs');
    let newAttrs = this.get('newAttrs');

    if (oldAttrs && oldAttrs !== newAttrs) {
      this.map.move({ from: oldAttrs, to: newAttrs });
    }

    this.set('_previousAttrs', newAttrs);
  }
});

Or maybe you can use this ember-diff-attrs addon for a while.

starshine wang
  • 616
  • 1
  • 8
  • 13