3

now in the old Angular code we were using

@Input() foo = '';

ngOnChanges(changes: Record<string, SimpleChange | undefined>): void {
  if (changes['foo']) {
    if (changes['foo'].firstChange) {
      // some logic for first change
      console.log('first change', changes['foo'].currentValue);
    } else {
      // another logic for 2+ changes
      console.log(
        '2+ changes',
        changes['foo'].previousValue,
        changes['foo'].currentValue
      );
    }
  }
}

how to achieve the same behavior using the new signal input and effect?

I have read that I can convert the signal to observable and use pairwise, but pairwise doesn't emit for first value at all

here is simple example to try it out https://stackblitz.com/edit/stackblitz-starters-ymnhaw?file=src%2Fcmp%2Fcmp.component.ts

why I'm asking this question? because in the RFC for signal components, it's mentioned that

  1. Signal-based components will retain the following lifecycle methods ngOnInit and ngOnDestroy only
  2. ngOnChanges - is used to observe changes to inputs. As inputs are signal-based, computed can be used to derive new values, or effect to react side-effectfully.

enter image description here

8
  • 1
    instead of pairwise maybe you could use map and convert to an object with a firstChange property: map((value, i) => ({ value, firstChange: i === 0 })) StackBlitz Commented Feb 9, 2024 at 19:03
  • 2
    ngOnChanges() works with signal inputs. Commented Feb 10, 2024 at 4:59
  • @BizzyBob but that way I lose access to the old value, I need both if it's the first change and what is the old value Commented Feb 10, 2024 at 10:19
  • @OZ_ yes it works, but they mentioned that the life cycle hooks will not be part of the future of Angular Commented Feb 10, 2024 at 10:20
  • @Robert they will provide an alternative, that's for sure. And a schematics to migrate the existing code. Commented Feb 10, 2024 at 10:21

2 Answers 2

1

You can store previous value in some (private) property and in effect just update it with the latest value, but before updating you can handle your change:

  value = input.required<number>();
  #prev: number | null = null;

  #changes = effect(() => {
    console.log(this.value(), this.#prev);
    // you can do your changes handling here

    // then do the update
    this.#prev = this.value();
  });

result example: https://stackblitz.com/edit/stackblitz-starters-whk2kj?file=src%2Fmain.ts

Sign up to request clarification or add additional context in comments.

Comments

0

I'm having the same issue. It seems like a missing piece of functionality that is needed in newer versions of Angular.

That said, here is how I'm achieving it in Angular 17/18 using effect:

foo = input<string>();

private prevFoo: string;

private onFooChanged = effect(
  () => {
    const foo = this.foo();

    if (this.prevFoo === undefined) {
      // this is the first change, do something...
    } else {
      // this is not the first change, do something else...
    }

    this.prevFoo = foo;
  }
);

That does look like too much boilerplate for such a simple thing. I hope they introduce some utility for that.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.