local-storage.service.ts
· 1.9 KiB · TypeScript
Raw
import { Injectable } from '@angular/core';
import { fromEvent, merge, Observable, Subject } from 'rxjs';
import { filter, map, startWith } from 'rxjs/operators';
export interface LocalStorageObject {
name: string;
value: string | null;
}
const deserializeValue = <T>(value: string): T => {
try {
return JSON.parse(value);
} catch {
return value as unknown as T;
}
};
@Injectable({
providedIn: 'root',
})
export class LocalStorageService {
private _storage = window.localStorage;
private _storageUpdateNotifier$ = new Subject<LocalStorageObject | null>();
storageUpdates$ = this._storageUpdateNotifier$.asObservable();
initLocalStorage(storageObjs: LocalStorageObject[]): void {
if (this._isLocalStorageEnabled()) {
storageObjs.forEach(({ name, value }) => {
this._storage.setItem(name, value);
});
}
}
setItem(key: string, value: string): void {
this._storage.setItem(key, value);
this._storageUpdateNotifier$.next({ name: key, value });
}
getItem(key: string): any {
const retrieved = this._storage.getItem(key);
try {
return deserializeValue(retrieved);
} catch {
return retrieved;
}
}
removeItem(key: string): void {
this._storage.removeItem(key);
this._storageUpdateNotifier$.next({ name: key, value: null });
}
clear(): void {
this._storage.clear();
this._storageUpdateNotifier$.next(null);
}
getUpdatesForKey<T>(key: string): Observable<T> {
return merge(
fromEvent(window, 'storage').pipe(
filter((event: StorageEvent) => event.key === key),
map(data => deserializeValue(data.newValue))
),
this.storageUpdates$.pipe(
filter(update => update.name === key),
map(update => deserializeValue(update.value))
)
).pipe(startWith(this.getItem(key) || false));
}
private _isLocalStorageEnabled(): boolean {
try {
const key = `__storage__test`;
this._storage.setItem(key, null);
this._storage.removeItem(key);
return true;
} catch (e) {
return false;
}
}
}
1 | import { Injectable } from '@angular/core'; |
2 | import { fromEvent, merge, Observable, Subject } from 'rxjs'; |
3 | import { filter, map, startWith } from 'rxjs/operators'; |
4 | |
5 | export interface LocalStorageObject { |
6 | name: string; |
7 | value: string | null; |
8 | } |
9 | |
10 | const deserializeValue = <T>(value: string): T => { |
11 | try { |
12 | return JSON.parse(value); |
13 | } catch { |
14 | return value as unknown as T; |
15 | } |
16 | }; |
17 | |
18 | @Injectable({ |
19 | providedIn: 'root', |
20 | }) |
21 | export class LocalStorageService { |
22 | private _storage = window.localStorage; |
23 | |
24 | private _storageUpdateNotifier$ = new Subject<LocalStorageObject | null>(); |
25 | |
26 | storageUpdates$ = this._storageUpdateNotifier$.asObservable(); |
27 | |
28 | initLocalStorage(storageObjs: LocalStorageObject[]): void { |
29 | if (this._isLocalStorageEnabled()) { |
30 | storageObjs.forEach(({ name, value }) => { |
31 | this._storage.setItem(name, value); |
32 | }); |
33 | } |
34 | } |
35 | |
36 | setItem(key: string, value: string): void { |
37 | this._storage.setItem(key, value); |
38 | this._storageUpdateNotifier$.next({ name: key, value }); |
39 | } |
40 | |
41 | getItem(key: string): any { |
42 | const retrieved = this._storage.getItem(key); |
43 | try { |
44 | return deserializeValue(retrieved); |
45 | } catch { |
46 | return retrieved; |
47 | } |
48 | } |
49 | |
50 | removeItem(key: string): void { |
51 | this._storage.removeItem(key); |
52 | this._storageUpdateNotifier$.next({ name: key, value: null }); |
53 | } |
54 | |
55 | clear(): void { |
56 | this._storage.clear(); |
57 | this._storageUpdateNotifier$.next(null); |
58 | } |
59 | |
60 | getUpdatesForKey<T>(key: string): Observable<T> { |
61 | return merge( |
62 | fromEvent(window, 'storage').pipe( |
63 | filter((event: StorageEvent) => event.key === key), |
64 | map(data => deserializeValue(data.newValue)) |
65 | ), |
66 | this.storageUpdates$.pipe( |
67 | filter(update => update.name === key), |
68 | map(update => deserializeValue(update.value)) |
69 | ) |
70 | ).pipe(startWith(this.getItem(key) || false)); |
71 | } |
72 | |
73 | private _isLocalStorageEnabled(): boolean { |
74 | try { |
75 | const key = `__storage__test`; |
76 | this._storage.setItem(key, null); |
77 | this._storage.removeItem(key); |
78 | return true; |
79 | } catch (e) { |
80 | return false; |
81 | } |
82 | } |
83 | } |