Angular monkey-patch ngOnChanges lifecycle hook

38 views Asked by At

I want to monkey patch the ngOnChanges life cycle hook so that I can execute some custom logic whenever ngOnChanges is executed. With the following code snippet I'm already able to to this:

export function changes$<T extends Record<string, any>>(target: any) {

  const inputs = target.constructor.ɵcmp.inputs;
  const origNgOnChanges = target.constructor?.prototype?.ngOnChanges;
  const origNgOnInit = target.constructor?.prototype?.ngOnInit;

  target.constructor.prototype.ngOnInit = function (): void {
    const simpleChangesToPass: TypedSimpleChanges<T> = {};
    Object.keys(inputs)
      .map((key) => inputs[key])
      .forEach((inputKey) => {
        simpleChangesToPass[inputKey] = new SimpleChange(
          this[inputKey],
          this[inputKey],
          true
        );
      });

    console.log(mapChanges(simpleChangesToPass));

    if (origNgOnInit) {
      origNgOnInit.apply(target.constructor.prototype);
    }
  };

  // overwrite the original ngOnChanges life cycle hook
  target.constructor.prototype.ngOnChanges = function (
    simpleChanges: TypedSimpleChanges<T>
  ): void {
    console.log('ngOnChanges ', simpleChanges);
    console.log(simpleChanges);
    const mappedChanges = mapChanges(simpleChanges);
    if (mappedChanges === undefined) {
      return;
    }
    console.log(mapChanges(simpleChanges));

    if (origNgOnChanges) {
      origNgOnChanges.apply(target.constructor.prototype, [simpleChanges]);
    }
  };

  return stream$.asObservable().pipe(
    filter(isNotUndefined),
    scan((acc, curr) => ({ ...acc, ...curr }), {} as T),
    distinctUntilChanged((previous: T, current: T) => {
      const keys = Object.keys(current);
      return keys.every((key) => {
        return current[key] === previous[key];
      });
    })
  );
}

However I face the Problem that if a new Input arrives I do not get the new value logged. Only after a second time a new input arrives I see in the log the value of the previous change. So I'm always one value behind the actual current value and I do not spot the issue.

Repro/Stackblitz: https://stackblitz.com/edit/stackblitz-starters-2rvjvp?file=src%2Fmain.ts

Hint: console.log is just a very simplified example of executing "custom logic"

0

There are 0 answers