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/bind.decorator';
|
||||||
export * from './decorators/required.decorator';
|
export * from './decorators/required.decorator';
|
||||||
export * from './decorators/debounce.decorator';
|
export * from './decorators/debounce.decorator';
|
||||||
|
export * from './decorators/on-change.decorator';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user