0

To preface this, I must clarify that I am using the legacy-controller and the legacy-view for the interim period while transitioning to Ember 2.3, found here:

https://github.com/emberjs/ember-legacy-controllers

Now, I have a property called currentTopPost on my (legacy) controller.

In Ember 1.7, I had this setup:

// before observer
currentTopPostBeforeObserver: function(){
...
}.observesBefore('currentTopPost'),

// observer
currentTopPostBeforeObserver: function(){
...
}.observes('currentTopPost'),

The reason I had it this way was that when the currentTopPost changed, I wanted it save the old topPost before it switched its value to the new property, as it was a Post object (I had a Post model).

Of course, in 1.7, I saved the old post in the beforeObserver and then did whatever else I had to do in the observer. Now, In Ember 2.3, I have this set up:

currentTopPostObserver: Ember.observer('currentTopPost', function(){
...

}),

Which works fine as far as performing functions with the new value goes. But I've lost the ability to process an action before the value changes. Now according to an answer to this question:

How can an observer find out the before and after values of the observed property in Ember.js?

the observesBefore function has been deprecated and we should be following this:

doSomething: Ember.observer( 'foo', function() {
  var foo = this.get('foo');
  var oldFoo = this.get('_oldFoo');

  if (foo === oldFoo) { return; }

  // Do stuff here

  this.set('_oldFoo', foo);
})

However, on trying to use this.get("_oldCurrentTopPost"), I get nothing. How do I access the old value of this property before it changes ?

Community
  • 1
  • 1
Darshan
  • 937
  • 3
  • 15
  • 27

2 Answers2

3

What I use as a replacement is:

propWillChange(prop) {
  //your new before observer
},

propDidChange: Ember.observer('prop', function() {

  let prop = this.get('prop');

  if (this._oldProp !== prop) {
    this.propWillChange(this._oldProp);
    this._oldProp = prop;
  }

  //Do stuff

})

Of course, on the first run, _oldProp will be undefined, but that's expected, right? It is the first time prop is being changed.

I also disagree that observers shouldn't be used. I agree that observers should be avoided if possible, because many people don't fully grasp their side-effects, but in many cases they are very useful, especially when building 3rd party plugin integrations.

Since the question specifically asks about a beforeObserver replacement, here it is. However, I recommend to reconsider if your use case can be rebuilt without observers if possible.

Twiddle: https://ember-twiddle.com/045b7b9c1562ceb6bbdc

miguelcobain
  • 4,734
  • 4
  • 32
  • 45
  • I should have used the term "should be avoided where possible" instead of "considered harmful", I like this approach as well. – Nicholas Kircher Feb 12 '16 at 00:32
  • I'm trying to implement this - and I love this approach, by the way - but I can't access the old prop. I have tried: this._oldProp, this._oldCurrentTopPost, this.get("_oldCurrentTopPost") and this.get("_oldProp"). I think I'm messing up the naming convention or something. I went by the observed property's name, in this case 'currentTopPost' and tried adding 'old' to it. Also, I've tested it going from undefined to choosing first, then choosing a second, but all 'oldProp's are still undefined. – Darshan Feb 12 '16 at 16:10
  • @Darshan I've updated the answer with a twiddle proving that it works. I also updated a little missing paren that was missing to close `observer` function. – miguelcobain Feb 12 '16 at 16:54
  • @Darshan Did this help? – miguelcobain Feb 15 '16 at 12:27
  • @Darshan Did this meet your requirements? Can this be accepted? – miguelcobain Feb 28 '16 at 22:44
0

As far as I can tell, there is no particularly nice way to get that mechanism back. Observers themselves are "considered harmful" in many cases, but I'll try my best to give you a practical alternative solution.

The best quick and relatively dirty way to do this that I can think of is to make a "proxy" computed property with a getter and setter. Within the setter you can get the previous value of the "real" property, call out to a function to do whatever, and then set the new value on the real property.

Here's an example that you could use:

myProxyProperty: Ember.computed('myRealProperty', {
  get() {
    return this.get('myRealProperty');
  },
  set(key, value) {
    const oldValue = this.get('myRealProperty');

    this.doSomethingWithOldValue(oldValue);

    this.set('myRealProperty', oldValue);
  }
})

Unfortunately I don't know of a better way of doing this in new Ember at the moment.

  • I suggest going with Miguel's approach above, I'll leave this here as an alternative though. – Nicholas Kircher Feb 12 '16 at 00:35
  • I think the above wanted to do `this.set('myRealProperty', value)`. As it is, I think it will keep the old value and never set the new – shane Nov 03 '16 at 19:05