How to listen for value changes from class property TypeScript - Angular
You can still check component's field members value change by KeyValueDiffers
via DoCheck
lifehook.
import { DoCheck, KeyValueDiffers, KeyValueDiffer } from '@angular/core';
differ: KeyValueDiffer<string, any>;
constructor(private differs: KeyValueDiffers) {
this.differ = this.differs.find({}).create();
}
ngDoCheck() {
const change = this.differ.diff(this);
if (change) {
change.forEachChangedItem(item => {
console.log('item changed', item);
});
}
}
see demo.
I think the nicest solution to your issue is to use a decorator that replaces the original field with a property automatically, then on the setter you can create a SimpleChanges
object similar to the one created by angular in order to use the same notification callback as for angular (alternatively you could create a different interface for these notifications, but the same principle applies)
import { OnChanges, SimpleChanges, DoCheck, SimpleChange } from '@angular/core';
function Watch() : PropertyDecorator & MethodDecorator{
function isOnChanges(val: OnChanges): val is OnChanges{
return !!(val as OnChanges).ngOnChanges
}
return (target : any, key: string | symbol, propDesc?: PropertyDescriptor) => {
let privateKey = "_" + key.toString();
let isNotFirstChangePrivateKey = "_" + key.toString() + 'IsNotFirstChange';
propDesc = propDesc || {
configurable: true,
enumerable: true,
};
propDesc.get = propDesc.get || (function (this: any) { return this[privateKey] });
const originalSetter = propDesc.set || (function (this: any, val: any) { this[privateKey] = val });
propDesc.set = function (this: any, val: any) {
let oldValue = this[key];
if(val != oldValue) {
originalSetter.call(this, val);
let isNotFirstChange = this[isNotFirstChangePrivateKey];
this[isNotFirstChangePrivateKey] = true;
if(isOnChanges(this)) {
var changes: SimpleChanges = {
[key]: new SimpleChange(oldValue, val, !isNotFirstChange)
}
this.ngOnChanges(changes);
}
}
}
return propDesc;
}
}
// Usage
export class MyClass implements OnChanges {
//Properties what I want to track !
@Watch()
myProperty_1: boolean = true
@Watch()
myProperty_2 = ['A', 'B', 'C'];
@Watch()
myProperty_3 = {};
constructor() { }
ngOnChanges(changes: SimpleChanges) {
console.log(changes);
}
}
var myInatsnce = new MyClass(); // outputs original field setting with firstChange == true
myInatsnce.myProperty_2 = ["F"]; // will be notified on subsequent changes with firstChange == false