add on change decorator
This commit is contained in:
parent
4f0d8022ed
commit
b55e3bf0dd
60
src/lib/utils/decorators/on-change.decorator.ts
Normal file
60
src/lib/utils/decorators/on-change.decorator.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { FunctionKeys } from '../types/utility-types';
|
||||
|
||||
export interface SimpleChange<T> {
|
||||
readonly previousValue: T;
|
||||
readonly currentValue: T;
|
||||
readonly isFirstChange: boolean;
|
||||
}
|
||||
|
||||
export type CallBackFunction<T> = (value: T, change: SimpleChange<T>) => void;
|
||||
|
||||
type TypedPropertyDecorator<C> = (target: C, key: PropertyKey) => void;
|
||||
|
||||
const CACHED_VALUE_KEY = Symbol();
|
||||
const IS_FIRST_CHANGE_KEY = Symbol();
|
||||
|
||||
interface Instance<T> {
|
||||
[CACHED_VALUE_KEY]: T;
|
||||
[IS_FIRST_CHANGE_KEY]: boolean;
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export function OnChange<T>(callback: CallBackFunction<T> | string): PropertyDecorator;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function OnChange<T, C extends Object = Object>(callback: CallBackFunction<T> | FunctionKeys<C>): TypedPropertyDecorator<C>;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export function OnChange<T, C extends Object = Object>(callback: CallBackFunction<T> | FunctionKeys<C>): TypedPropertyDecorator<C> {
|
||||
return function _onChange(target: C, key: PropertyKey) {
|
||||
Object.defineProperty(target, key, {
|
||||
set(value: T) {
|
||||
const instance = this as Instance<T>;
|
||||
const callBackFn = <CallBackFunction<T>>(typeof callback === 'string' ? instance[callback] : callback);
|
||||
if (!callBackFn) {
|
||||
throw new Error(`Cannot find method ${String(callback)} in class ${target.constructor.name}`);
|
||||
}
|
||||
|
||||
instance[IS_FIRST_CHANGE_KEY] = instance[IS_FIRST_CHANGE_KEY] === undefined;
|
||||
|
||||
// No operation if new value is same as old value
|
||||
if (!instance[IS_FIRST_CHANGE_KEY] && instance[CACHED_VALUE_KEY] === value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldValue = instance[CACHED_VALUE_KEY];
|
||||
instance[CACHED_VALUE_KEY] = value;
|
||||
|
||||
const simpleChange: SimpleChange<T> = {
|
||||
previousValue: oldValue,
|
||||
currentValue: instance[CACHED_VALUE_KEY],
|
||||
isFirstChange: instance[IS_FIRST_CHANGE_KEY]
|
||||
};
|
||||
|
||||
callBackFn.call(instance, instance[CACHED_VALUE_KEY], simpleChange);
|
||||
},
|
||||
get(): T {
|
||||
return (this as Instance<T>)[CACHED_VALUE_KEY];
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
@ -8,3 +8,4 @@ export * from './types/tooltip-positions.type';
|
||||
export * from './decorators/bind.decorator';
|
||||
export * from './decorators/required.decorator';
|
||||
export * from './decorators/debounce.decorator';
|
||||
export * from './decorators/on-change.decorator';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user