A small but powerful TypeScript/ES5 library that simplifies the use of HTML5 Web Storage APIs in your models
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
graphics
lib
.gitignore
.npmignore
.travis.yml
LICENSE
README.md
package.json
tsconfig.json
tslint.json

README.md

local-motive

A small but powerful TypeScript/ES5 library that simplifies the use of HTML5 Web Storage APIs in your models

logo

npm version build status

Installation

To install Local Motive, run:

$ npm install local-motive --save

Usage

Local Motive provides @LocalStorage and @SessionStorage decorators that handle storage of model and nested model changes. To use them, just extend the provided LocalModel abstract class.

LocalModel requires a storagePath field, which is used to support storing changes to fields and nested models. It should be provided in the constructor of your derived model class. In addition, LocalModel provides a subpath() method for use in generating storage paths for nested models. See the example below.

// person.model.ts //

import { LocalModel, LocalStorage, SessionStorage } from 'local-motive';
import { Phone } from './phone.model';

export class Person extends LocalModel {

  @LocalStorage()
  fullName: string;

  @SessionStorage()
  authKey: string;

  // Differing paths here avoid conflicting storage keys for
  // `primaryPhone.number` and `secondaryPhone.number`
  primaryPhone = new Phone(this.subpath('phone1'));
  secondaryPhone = new Phone(this.subpath('phone2'));
}
// phone.model.ts //

import { LocalModel, LocalStorage, SessionStorage } from 'local-motive';

export class Phone extends LocalModel {

  @LocalStorage()
  number: string;
}

Now, when you modify values on your models, including nested models, the data will be persisted automatically.

This is especially useful if you're using a framework like Angular, where you can bind directly to locally-stored models in your views:

// demo.component.ts //

import { Component } from '@angular/core';
import { Person } from './person.model';

@Component({
  selector: 'app-demo',
  template: `
    <h3>Person 1</h3>
    <input placeholder="Full Name" [(ngModel)]="person1.fullName">
    <input placeholder="Auth Key" [(ngModel)]="person1.authKey">
    <input placeholder="Primary Phone" [(ngModel)]="person1.primaryPhone.number">
    <input placeholder="Secondary Phone" [(ngModel)]="person1.secondaryPhone.number">

    <h3>Person 2</h3>
    <input placeholder="Full Name" [(ngModel)]="person2.fullName">
    <input placeholder="Auth Key" [(ngModel)]="person2.authKey">
    <input placeholder="Primary Phone" [(ngModel)]="person2.primaryPhone.number">
    <input placeholder="Secondary Phone" [(ngModel)]="person2.secondaryPhone.number">
  `
})
export class DemoComponent {

  // Paths provided must be unique across app to avoid
  // storage key conflicts (and thus overwritten data)
  person1 = new Person('person1');
  person2 = new Person('person2');
}

Other Features

Decorators

The @LocalStorage and @SessionStorage decorators have many more features, like:

  • Support for non-string types like number, object, array, and null
  • Custom storage key
  • Default value
  • Custom serialization and deserialization
  • Support for inherited properties

For more info, see the decorators source. For additional usage examples, see the test spec.

LocalModel

LocalModel provides the following interface and can even be used without decorators, if desired:

abstract class LocalModel {

  constructor(private storagePath: string);

  /**
   * Generates a storage subpath, relative to this model's path.
   * @param path Path to place under this model's path.
   * @param index Optional index value for generating an indexed path.
   */
  subpath(path: string, index?: number): string;

  /**
   * Stores a value in local or session storage.
   * @param key Storage key, relative to this model's storage path.
   * @param value Value to store.
   * @param session Whether or not to store in session storage.
   * Defaults to false.
   */
  store(key: string, value: string, session: boolean = false);

  /**
   * Retrieves a value from local or session storage.
   * @param key Storage key, relative to this model's storage path.
   * @param session Whether or not to store in session storage.
   * Defaults to false.
   */
  load(key: string, session: boolean = false): string;

  /**
   * Removes a value from local or session storage.
   * @param key Storage key, relative to this model's storage path.
   * @param session Whether or not to remove from session storage.
   * Defaults to false.
   */
  delete(key: string, session: boolean = false);

  /**
   * Removes all values from both local and session storage for
   * this model and any submodels.
   */
  clear();

For usage examples, see the test spec.

A Word of Caution with Initialized Fields

While fields that have initial values can be decorated with the @LocalStorage or @SessionStorage decorators, the outcome will likely not be the desired one. This is because an initial value will overwrite any value in storage for a given decorated field. To provide an initial value for a decorated field that will only apply if no value is currently stored, use the defaultValue parameter in your decorator. See the decorators source for more info.

License

MIT © Andrew Meyer