Last active
April 4, 2023 16:57
-
-
Save ccarrasc/fbf71c662a32775f9b93d85481b8d59d to your computer and use it in GitHub Desktop.
Wrapping storage access with BehaviorSubject for Angular
This file contains 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
import { Injectable } from '@angular/core'; | |
import StorageService from './storage.service'; | |
@Injectable() | |
export class LocalStorageService extends StorageService { | |
private _storage = localStorage; | |
constructor() { | |
super(); | |
} | |
protected get storage(): Storage { | |
return this._storage; | |
} | |
} |
This file contains 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
import { Injectable } from '@angular/core'; | |
import StorageService from './storage.service'; | |
@Injectable() | |
export class SessionStorageService extends StorageService { | |
private _storage = sessionStorage; | |
constructor() { | |
super(); | |
} | |
protected get storage(): Storage { | |
return this._storage; | |
} | |
} |
This file contains 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
import { Observable, BehaviorSubject } from 'rxjs/Rx'; | |
abstract class StorageService { | |
private itemSources: Map<string, BehaviorSubject<string>> = new Map(); | |
protected abstract get storage(): Storage; | |
constructor() { | |
addEventListener('storage', (event: StorageEvent) => { | |
if (event.key) { | |
if (this.itemSources.has(event.key)) { | |
this.itemSources.get(event.key).next(event.newValue); | |
} | |
} | |
}); | |
} | |
getItem(key: string): Observable<string> { | |
if (!this.itemSources.has(key)) { | |
this.itemSources.set(key, new BehaviorSubject<string>(this.storage.getItem(key))); | |
} | |
return this.itemSources.get(key).asObservable(); | |
} | |
setItem(key: string, value: string) { | |
try { | |
this.storage.setItem(key, value); | |
if(this.itemSources.has(key)) { | |
this.itemSources.get(key).next(this.storage.getItem(key)); | |
} | |
} | |
catch (error) { | |
this.itemSources.get(key).error(error); | |
} | |
} | |
removeItem(key: string) { | |
this.storage.removeItem(key); | |
if (this.itemSources.has(key)) { | |
this.itemSources.get(key).next(this.storage.getItem(key)); // Expect to be null | |
this.itemSources.delete(key); | |
} | |
} | |
clear() { | |
this.storage.clear(); | |
this.itemSources.forEach((itemSource: BehaviorSubject<string>) => { | |
itemSource.next(null); | |
itemSource.complete(); | |
}); | |
this.itemSources.clear(); | |
} | |
} | |
export default StorageService; |
@VincentQueignec I don't think so, but I do not have any unit tests to validate that and this is also a very old snippet.
From what I see, StorageService
is abstract, and the concrete implementations specify the storage type. I don't see how you can cross into the wrong storage when using a concrete type (see the getter for storage
).
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Your StorageEvent can be fired from local and session from my understanding ? Am I wrong ?
If yes, if you have the same key from your local and session storage, you might override the wrong storage in addition of the good one.