Last active
June 3, 2022 09:01
-
-
Save secretorange/6297bdcf0e656a3c39aa8709875f0f79 to your computer and use it in GitHub Desktop.
A simple single file Angular State Service
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Injectable({ | |
providedIn: "root", | |
}) | |
export class ExampleAppStateService extends StateService { | |
public get company(): StateItem<CompanyModel> { | |
return this.get("company", () => new StateItem<CompanyModel>()); | |
} | |
public get project(): StateItem<ProjectModel> { | |
return this.get( | |
"project", | |
() => | |
new StateItem<ProjectModel>((item: ProjectModel) => { | |
// Add code here to do suff when a project is refresh. | |
// Perhaps clear out related child state | |
}) | |
); | |
} | |
} | |
export class StateService { | |
private items = {}; | |
protected get<T>(key: string, build: () => StateItem<T>) { | |
if (!this.items[key]) { | |
this.items[key] = build(); | |
} | |
return this.items[key]; | |
} | |
} | |
export class StateItem<T> { | |
private onSet: (item: T) => void; | |
constructor(onSet: (item: T) => void = null) { | |
this.onSet = onSet; | |
} | |
private current: T = null; | |
private $ = new BehaviorSubject<T>(null); | |
// Used for adding items to an array | |
public add(item: any) { | |
if (!this.current || !Array.isArray(this.current)) { | |
return; | |
} | |
this.current.push(item); | |
this.$.next(this.current); | |
} | |
public get value(): T { | |
return this.current; | |
} | |
public get observable(): BehaviorSubject<T> { | |
return this.$; | |
} | |
public set value(item: T) { | |
// Update current *before* calling next() | |
this.current = item; | |
if (this.onSet) { | |
this.onSet(item); | |
} | |
this.$.next(item); | |
} | |
public clear() { | |
this.value = null; | |
} | |
public subscribe(next: (value: T) => void): Subscription { | |
return this.$.subscribe(next); | |
} | |
// Allow the client to wait until the StateItem has a value | |
public require(): Promise<T> { | |
if (this.value) { | |
return Promise.resolve(this.value); | |
} | |
return new Promise((resolve) => { | |
let resolved = false; | |
this.$.pipe(takeWhile((value) => !resolved)).subscribe((value) => { | |
if (value) { | |
resolved = true; | |
resolve(value); | |
} | |
}); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
After injecting your service you can do stuff like:
Waiting for a particular state item to load is super useful when refreshing the page and data is being loaded asynchronously by multiple components.