@ng2plus/web-storage
v1.1.2
Published
Ultimate web storage for Angular2
Downloads
4
Readme
Ultimate web storage for Angular2
Features:
- custom prefix
- built-in
localStorage
andsessionStorage
providers webStorage
Pipe- custom providers
- switching providers on the fly
- notification options:
get
,set
,remove
,removeAll
- notifications broadcasting (1):
set
,remove
,removeAll
- rich and chainable API:
set
,get
,pull
,has
,length
,remove
,removeAll
,forEach
,keys
,getAll
and more - currying style API for one line usage in
Promis
es Observable
s support by wrappingPromis
es intoObservable
s- errors emitter
- well tested (all possible parts are covered)
- built on top of TypeScript and ES6, packed via webpack
- clean package after
npm 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.
Installation
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
Pre-requirements
You should manually shim ES6
(es2015
) features such as Promise
, startsWith
and also ES7
(es2016
) feature includes
.
Setup
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 {}
Advanced Setup
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.
Configuration object
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 whenremoveAll
method is called
See NotifyOptions
interface for details
NotifyOptions
can be exported
Usage
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!
}
}
API
Methods
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 valueitem
- any object to storereplacer
in case when the object is not serializable you can define replacer method, which is the same as the 3rd parameter ofJSON.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 valuedefaultVal
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 ofJSON.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 valuedefaultVal
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 ofJSON.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 value
Returns 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: currentitem
and itskey
without prefix.
Chainable. Returns WebStorageService
itself.
Storage provider should be iterable.
remove
Delete item from the storage.
remove<T>(key: string): T
key
- akey
name to delete
Returns 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 object
Chainable. 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 belocalStorage
orsessionStorage
value
- instance of class that implementsStorageProvider
interface. Find default providers for examplesuseIt
- use added provider
Chainable. 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.
Properties
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));
Subscriptions
onError
Emits events when an internal error occurs or item can't be set or retrieve from storage.
onError: ReplaySubject<number>
onSet
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
onGet
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
onRemove
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
onRemoveAll
Emits event when removeAll
method is called. Triggers only when notifyOn.onRemoveAll
option is true
.
onRemoveAll: Subject<number>
Emits number of removed items.
onMessage
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
Advanced Usage
Observables
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));
Custom Providers
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);