Search code examples
angularangular-signals

Possible to access the old value in Angular 16's effect() function (similar to Vue.js watch)?


In Vue.js, the watch function gets the new and old watched value passed as arguments, which is really helpful in case the differences matter, or when I want to release the previous allocated resource.

Now in Angular 16, we finally have signal, computed, and effect. effect() seems to be the equivalent of the watch in Vue.js. But is it there also possible to get access to the old value?

The Angular API docs only mention onCleanup. As effect does not operate on an expression as in Vue, it might not be possible to store a previous value in a generic way.

Is there a workaround?


Solution

  • Effect does not give an old value, as signals only store the current value. Angular shipped an rxjs interop package, @angular/core/rxjs-interop, which help you for this kind of usecase. You can use the toObservable function as follows to achieve what you want:

    /**
      * Signal version of count
      */
    count = signal(0);
    
    /**
      * Straight conversion to observable
      */
    count$ = toObservable(this.count);
    
    /**
      * Pairwise conversion to achieve old/new functionality
      */
    countPrevAndCurr$ = this.count$.pipe(
      pairwise(),
      map(([oldVal, newVal]) => {
        console.log('Old Value (Observable): ', oldVal);
        console.log('New Value (Observable): ', newVal);
        return { old: oldVal, new: newVal };
      })
    );
    

    Here is a StackBlitz showing the functionality in action.

    Note: At the time of writing this answer both the Angular Signals and Rxjs Interop packages were in developer preview so this is potentially subject to change.