localStorage
and sessionStorage
providerswebStorage
Pipeget
, set
, remove
, removeAll
set
, remove
, removeAll
set
, get
, pull
, has
, length
, remove
, removeAll
, forEach
, keys
, getAll
and morePromis
esObservable
s support by wrapping Promis
es into Observable
snpm install
without redundant trash(1) broadcasting is available via BroadcastChannel API. You have to make sure that your target platform supports the API in order to use this feature. You also can include polyfill that adds
BroadcastChannel
function towindow
. IfBroadcastChannel
is not supported by the platform and there is no polyfill fot that then notifications broadcasting will be disabled.
npm install @ng2plus/web-storage
After installation UMD-style modules will be available too:
./node_modules/@ng2plus/web-storage/bundles/web-storage.umd.js
./node_modules/@ng2plus/web-storage/bundles/web-storage.umd.min.js
You should manually shim ES6
(es2015
) features such as Promise
, startsWith
and also ES7
(es2016
) feature includes
.
Include WebStorageService
and its config in your root module.
...
import {
WebStorageService,
WEB_STORAGE_DECLARATIONS,
WEB_STORAGE_SERVICE_CONFIG,
webStorageConfigDefault
} from '@ng2plus/web-storage';
@NgModule({
...
declarations: [...WEB_STORAGE_DECLARATIONS],
providers: [
WebStorageService,
{provide: WEB_STORAGE_SERVICE_CONFIG, useValue: webStorageConfigDefault}
]
})
export class AppModule {}
You can change WebStorage
's setting by providing custom configuration object.
import {
WebStorageService,
WEB_STORAGE_SERVICE_CONFIG
} from '@ng2plus/web-storage';
const webStorageConfig = {
prefix: 'ng2plus'
};
@NgModule({
...
providers : [
WebStorageService,
{provide: WEB_STORAGE_SERVICE_CONFIG, useValue: webStorageConfig}
]
})
export class AppModule {}
It's not necessarily to provide all the options. For those which are missing will be set default values.
Through the configuration object you can customize storage's behavior. Below you can find its structure and default values.
{
prefix: '__',
provider: 'localStorage',
notifyOn: {
set: true,
get: true,
remove: true,
removeAll: true
}
}
See WebStorageConfig
interface for details
WebStorageConfig
can be exported
prefix
prefix: string = '__'
Prefix that will be added to each key of stored value to avoid name collisions.
provider
provider: string = 'localStorage'
Name of used storage provider. There are two embedded providers: localStorage
and sessionStorage
. But you can easily add a custom one (find more in API description).
notifyOn
notifyOn: <NotifyOptions> = { set: true, get: true, remove: true, removeAll: true }
set
- enable event emitter when item is added to storageget
- enable event emitter when item is got from storageremove
- enable event emitter when item is removed from storageremoveAll
- enable event emitter when removeAll
method is calledSee NotifyOptions
interface for details
NotifyOptions
can be exported
Now you can use it inside your Angular2 application.
import {WebStorageService} from '@ng2plus/web-storage';
@Component({
template: '\u2764 {{'favorite_framework' | webStorage}}'
})
export class FavoriteFramework {
constructor(private webStorage: WebStorageService) {
webStorage.set('favorite_framework', 'Angular2!');
console.log(webStorage.get('favorite_framework')); // Angular2!
}
}
set
set(key: string, item: any, replacer?: KeyValIterator\<any>): WebStorageService
Put an item
to the storage under a key
name
key
- a name of key for the value
item
- any object to store
replacer
in case when the object is not serializable you can define replacer method, which is the same as the 3rd parameter of JSON.stringify()
Chainable. Returns WebStorageService
itself.
get
Return an item
from the storage by a key
name.
get\<T>(key: string, defaultVal: any|KeyValIterator\<any> = null): T
key
- a name of key to retrieve the value
defaultVal
you can set the default value to return in case when key is not found. Also you can provide a callback that is equivalent of the 3rd parameter of JSON.parse()
Returns stored value.
pull
Return and remove an item
from the storage by a key
name.
pull\<T>(key: string, defaultVal?: any | KeyValIterator\<any>): T
key
- a name of key to retrieve the value
defaultVal
you can set the default value to return in case when key is not found. Also you can provide a callback that is equivalent of the 3rd parameter of JSON.parse()
Returns stored value and removes it from the storage.
StorageDictionary
interface can be exported
has
Check if an item exists in the in storage under a key
name.
has(key: string): boolean
key
- a name of checked valueReturns true if value exists, elsewhere - false.
keys
Get all keys in storage (only keys for current prefix will be returned).
keys(): string[]
Returns an array of keys.
Storage provider should be iterable.
getAll
Get all pairs key => value
in storage (only pairs for current prefix will be returned).
getAll(): StorageDictionary
Returns an array of objects representing values in the storage.
StorageDictionary
interface can be exported
forEach
Iterates over the items in the storage (only pairs for current prefix will be iterated).
forEach(fn: (item: any, key: string) => void, defaultVal?: any): WebStorageService
fn
- callback function that will be called with two arguments: current item
and its key
without prefix.Chainable. Returns WebStorageService
itself.
Storage provider should be iterable.
remove
Delete item from the storage.
remove\<T>(key: string): T
key
- a key
name to deleteReturns removed item.
removeAll
Deletes all the items from the storage (only item for current prefix will be deleted).
removeAll(): WebStorageService
Chainable. Returns WebStorageService
itself.
setup
Updates current storage instance with the configuration object.
setup(config: WebStorageConfig): WebStorageService
config
- see configuration objectChainable. Returns WebStorageService
itself.
WebStorageConfig
interface can be exported
addProvider
Add a custom storage provider. It should implement StorageProvider
interface in order to work properly.
addProvider(name: string, value: StorageProvider, useIt?: boolean): WebStorageService
name
- provider name. Can't be localStorage
or sessionStorage
value
- instance of class that implements StorageProvider
interface. Find default providers for examplesuseIt
- use added providerChainable. Returns WebStorageService
itself.
See StorageProvider
interface for details
StorageProvider
can be exported
useProvider
Use specific storage provider.
useProvider(providerName: string | DefaultWebStorageProvider): WebStorageService
providerName
- name of any added custom storage provider or one of defaults: localStorage
, sessionStorage
Chainable. Returns WebStorageService
itself.
length
length: number
Returns number of items in the storage (only items for current prefix are counted)
asPromise
Represents "promised" API that is easy to use chaining promises. All of methods are fallbacks to origins, e.g. asPromise.set === set
but in some cases the arguments order is different.
asPromise: { set: (key: string, replacer?: KeyValIterator<any>) => (item: any) => Promise<any>; get: <T>(key: string, defaultVal?: any) => () => Promise<T>; remove: <T>(key: string) => () => Promise<T>; removeAll: () => () => Promise<WebStorageService>; pull: <T>(key: string, defaultVal?: any) => () => Promise<T>; keys: () => () => Promise<string[]>; getAll: () => () => Promise<StorageDictionary>; };
The main idea of usage in promise chains, compare #1 and #2:
// #1
Promise.resolve('Octocat')
.then(val => {
webStorage.set('name', val);
return val;
})
.then(val => console.log(webStorage.get('name') === val));
// #2
Promise.resolve('Octocat')
.then(webStorage.asPromise.set('name')) // falls down previous value
.then(val => console.log(webStorage.get('name') === val));
In the example above it's clear that the first case is too verbose and requires to write extra callback. asPromise
interface tries to solve this by wrapping default methods into first class functions which return a promise.
Thus webStorage.asPromise.set('name')
returns a function that returns a promise. We can re-write it into 3 steps to simplify understanding:
// step 1
Promise.resolve('Octocat')
.then(val => {
const setAsPromise = webStorage.asPromise.set('name');
return setAsPromise(val);
})
.then(val => console.log(webStorage.get('name') === val));
// step 2
Promise.resolve('Octocat')
.then(val => webStorage.asPromise.set('name')(val))
.then(val => console.log(webStorage.get('name') === val));
// step 3
Promise.resolve('Octocat')
.then(webStorage.asPromise.set('name'))
.then(val => console.log(webStorage.get('name') === val));
Emits events when an internal error occurs or item can't be set or retrieve from storage.
onError: ReplaySubject\<number>
Emits event when item is put to storage. Triggers only when notifyOn.set
option is true
.
onSet: Subject\<WebStorageEventItem>
See WebStorageEventItem
interface for details
WebStorageEventItem
can be exported
Emits event when item is put to storage. Triggers only when notifyOn.get
option is true
.
onGet: Subject\<WebStorageEventItem>
See WebStorageEventItem
interface for details
WebStorageEventItem
can be exported
Emits event when item is removed from storage. Triggers only when notifyOn.onRemove
option is true
.
onRemove: Subject\<WebStorageEventItem>
See WebStorageEventItem
interface for details
WebStorageEventItem
can be exported
Emits event when removeAll
method is called. Triggers only when notifyOn.onRemoveAll
option is true
.
onRemoveAll: Subject\<number>
Emits number of removed items.
Works similar to StorageEvent
. When one of events (set
, get
or removeAll
) is happen (depends on notifyOn
configuration) the message is broadcasted to browsing contexts within the same origin.
onMessage: Subject\<WebStorageEvent>
This feature requires BroadcastChannel
API support or at least a polyfill
See WebStorageEvent
interface for details
WebStorageEvent
can be exported
Thanks to the asPromise
interface you can mix call to storage methods with observables:
Observable.fromPromise(webStorage.asPromise.set('name')('Octocat'))
.map(result => console.log(webStorage.get('name') === result));
With help on addProvider
method you can add custom storage implementation. Let's implement simple in memory key-value storage.
First of all a provider should implement StorageProvider
interface which requires to implement two methods: get
and validate
. get
method is used to retrieve an instance of provider and validate
method is used to check if the provider is available in current context (it calls only once, each time when useProvider
is called or the 3rd parameter of addProvider
method is true
).
Method get
has to return an instance of class which implements WebStorage
interface.
import {WebStorage} from '@ng2plus/web-storage';
// util decorator
function hidden(target, key) {
Object.defineProperty(target, key, {
enumerable: false,
writable: true,
value: {}
});
}
// define custom storage which implements `WebStorage` interface
class CustomStorage implements WebStorage {
@hidden reserved = {};
get length(): number {
let count = -1;
for (let i in Object.getOwnPropertyNames(this)) ++count;
return count;
}
clear(): void {
for (let i in this) this.removeItem(i);
}
getItem(key: string): any {
return (this.isReserved(key) ? this.reserved[key] : this[key]) || null
}
key(index: number): string {
let d = 0;
let found = '';
for (let i in Object.getOwnPropertyNames(this)) {
if (d === index) {
found = this[i];
break;
}
++d;
}
return found || null;
}
removeItem(key: string): void {
delete (this.isReserved(key) ? this.reserved : this)[key];
}
setItem(key: string, data: string): void {
if (this.isReserved(key)) {
this.reserved[key] = data;
} else {
this[key] = data;
}
}
private isReserved(key) {
return ['reserved', 'length', 'key'].includes(key);
}
[index: number]: string;
}
// implement provider for `CustomStorage`
class CustomStorageProvider implements StorageProvider {
private storage: CustomStorage = new CustomStorage();
get(): WebStorage {
return this.storage;
}
validate(): Observable<WebStorage> {
return new Observable<WebStorage>(observer => {
if (1 > 2) { // you can specify any kind of check you want
observer.error(`CustomStorage provider is not available`);
}
observer.next(this.get());
observer.complete();
});
}
// if you don't need any kind of validation, just return provider
/*
validate(): Observable<WebStorage> {
return Observable.of(this.get());
}
*/
}
// finally, register and use new provider
storage.addProvider('customProvider', new CustomStorageProvider(), true);