import { BehaviorSubject, Observable } from "rxjs"; // basically a wrapper for BehaviorSubject export class MutableObservable<T> { private Subject: BehaviorSubject<T>; constructor(value: T) { this.Subject = new BehaviorSubject<T>(value); this.getValue = this.getValue.bind(this); this.setValue = this.setValue.bind(this); this.asObservable = this.asObservable.bind(this); } getValue(): T { return this.Subject.getValue(); } setValue(value: T): void { return this.Subject.next(value); } asObservable() { return this.Subject.asObservable(); } } export class MutableObservableCollection<T extends { key: string | number }> { private subject: BehaviorSubject<T[]>; constructor(initialItems: T[] = []) { this.subject = new BehaviorSubject<T[]>(initialItems); } getItems(): T[] { return this.subject.getValue(); } asObservable(): Observable<T[]> { return this.subject.asObservable(); } setItems(newItems: T[]): void { this.subject.next(newItems); } updateItem(updatedItem: T): void { this.subject.next( this.getItems().map(item => item.key === updatedItem.key ? updatedItem : item) ); } addItem(newItem: T): void { this.subject.next([...this.getItems(), newItem]); } removeItem(key: string | number): void { this.subject.next(this.getItems().filter(item => item.key !== key)); } moveItemUp(key: string | number): void { const items = this.getItems(); const index = items.findIndex(item => item.key === key); // Als het item niet bestaat of al bovenaan staat, doe niets if (index <= 0) return; // Verwissel het item met het item ervoor const newItems = [...items]; [newItems[index - 1], newItems[index]] = [newItems[index], newItems[index - 1]]; this.subject.next(newItems); } moveItemDown(key: string | number): void { const items = this.getItems(); const index = items.findIndex(item => item.key === key); // Als het item niet bestaat of al onderaan staat, doe niets if (index === -1 || index >= items.length - 1) return; // Verwissel het item met het item erna const newItems = [...items]; [newItems[index], newItems[index + 1]] = [newItems[index + 1], newItems[index]]; this.subject.next(newItems); } getChangedItems(originalItems: T[]): T[] { return this.getItems().filter(item => { const original = originalItems.find(o => o.key === item.key); return original && JSON.stringify(original) !== JSON.stringify(item); }); } }
React
export function useMutableObservable<T>(subjectInput: MutableObservable<T>): [T, (value: T) => any, (changes: Partial<T>) => any] { const state = useMemo(() => ({ observable: subjectInput.asObservable(), setValue: subjectInput.setValue, getValue: subjectInput.getValue, updateValue: (_changes: Partial<T>) => 0 }), [subjectInput]); const [result, setResult] = useState<[T, (value: T) => any, (changes: Partial<T>) => any]>([state.getValue(), state.setValue, state.updateValue]); const resultRef = useRef(state.getValue()); resultRef.current = state.getValue(); useEffect(() => { if (!state?.observable) return; const subscription = state.observable.subscribe((x: any) => { if (x === resultRef.current) return; setResult([x, state.setValue, state.updateValue]); }); return () => subscription.unsubscribe(); }, [state]); return result; } export function useObservable<T>(subject: Observable<T | undefined>, initialValue?: T): T | undefined { const [data, setData] = useState<T | undefined>(initialValue); useEffect(() => { if (!subject) { return; } const subscription = subject.subscribe((x: any) => { setData(x); }); return () => subscription.unsubscribe(); }, [subject]); return data; }
941000cookie-checkTypescript MutableObservable and MutableObservableCollection