import { BehaviorSubject, Subscription } from 'ims-rxjs';
import { filter } from 'ims-rxjs/operators';
export interface EventData<T> {
evetntName: string;
object: T;
}
export interface PropertyChangeData<T> extends EventData<T> {
propertyName?: string;
value?: any;
oldValue?: any;
}
export function createObservableObject<T extends object>( source: T, ): T & {
subscribe: (
next?: (value: T) => void,
error?: (error: any) => void,
complete?: () => void,
) => Subscription;
unsubscribe(): void;
} {
let event: BehaviorSubject<PropertyChangeData<T>> = new BehaviorSubject({
evetntName: 'init',
object: undefined,
});
let subscription = new Subscription();
return new Proxy(source, {
get(target: T, p: PropertyKey, receiver: any): any {
if (p === 'subscribe') {
return (
next?: (value: any) => void,
error?: (error: any) => void,
complete?: () => void,
) => {
let subs = event
.pipe(
filter(
(res: PropertyChangeData<any>) => res.evetntName !== 'init',
),
)
.subscribe(
next,
e => {
subscription.remove(subs);
error(e);
},
() => {
subscription.remove(subs);
complete();
},
);
subscription.add(subs);
};
} else if (p === 'complete') {
return () => subscription.unsubscribe();
}
let _v = Reflect.get(target, p, receiver);
if (_v && typeof _v === 'object') {
let val = createObservableObject(_v);
subscription.add(
val.subscribe(res => {
event.next({
...res,
object: source,
propertyName: `${p as string}.${res.propertyName}`,
});
}),
);
return val;
}
return _v;
},
deleteProperty(target: T, p: PropertyKey): boolean {
event.next({
evetntName: 'drop',
object: source,
propertyName: p as string,
value: null,
oldValue: Reflect.get(target, p),
});
return Reflect.deleteProperty(target, p);
},
set(target: any, p: PropertyKey, value: any, receiver: any) {
if (!Reflect.has(target, p)) {
event.next({
evetntName: 'add',
object: source,
propertyName: p as string,
value: value,
oldValue: null,
});
return Reflect.set(target, p, value, receiver);
}
let oldValue = Reflect.get(target, p);
if (oldValue === value) {
return false;
}
event.next({
evetntName: 'update',
object: this,
propertyName: p as string,
value: source,
oldValue: oldValue,
});
return Reflect.set(target, p, value, receiver);
},
});
}
let obs = createObservableObject({
title: {
name: 'name1',
},
});
obs.subscribe(res => {
console.log(res);
});
obs.title.name = 'title2';
delete obs.title.name;
obs.title.name = 'titl3';
let obs2 = [1, 2, 3, 4];
let obs3 = createObservableObject(obs2);
obs3.subscribe(res => {
console.log(res);
debugger;
});
obs3[0] = 2;
複製代碼