Numeric Production Mechanism

    @d4h/ion-ngx-storage
    TypeScript icon, indicating that this package has built-in type declarations

    2.3.0 • Public • Published

    Codeship Status for D4H/ion-ngx-storage npm

    @d4h/ion-ngx-storage

    ion-ngx-storage is a module for Ionic 4/Angular applications which copies an application's NgRx root state to the native device or browser through Ionic/Storage.

    Installation

    npm install --save @d4h/ion-ngx-storage

    Configuration

    interface StorageConfig<T extends object = {}> {
      keys?: Array<string>;
      name: string;
    
      storage?: {
        description?: string;
        driver?: string | Array<string>;
        name?: string;
        size?: number;
        version?: number;
      }
    }
    • keys: Array<string>: Optional array of keys. When given, corresponding values are picked from the top-level state before write and after read.
    • name: string: The name of your application. Used internally as an Ionic Storage table key. All data is stored per application as a single object.
    • storage?: StorageConfig: Ionic Storage configuration.

    Default Configuration

    const defaultConfig: StorageConfig = {
      keys: [],
      name: 'ion_ngx_storage',
    
      storage: {
        name: 'ion_ngx_storage'
      }
    };

    Use

    Import StoreModule or call StoreModule.forRoot() with a configuration. ion-ngx-storage read and write the application state without any additional configuration. After effects initialization, ion-ngx-storage writes a serialized copy of the root state to the device after each action dispatch.

    Without Extra Configuration

    import { StorageModule } from '@d4h/ion-ngx-storage';
    
    @NgModule({
      imports: [
        StoreModule.forRoot(reducers, { metaReducers }),
        EffectsModule.forRoot(effects),
        StorageModule
      ]
    })
    export class AppModule {}

    With Extra Configuration

    import { StorageConfig, StorageModule } from '@d4h/ion-ngx-storage';
    
    // Optional configuration
    const storageConfig: StorageConfig<AppState> = {
      name: 'my_application_name'
    };
    
    @NgModule({
      imports: [
        StoreModule.forRoot(reducers, { metaReducers }),
        EffectsModule.forRoot(effects),
        StorageModule.forRoot(storageConfig)
      ]
    })
    export class AppModule {}

    Your application must import StoreModule.forRoot and EffectsModule.forRoot in order for ion-ngx-storage to function.

    Waiting for Hydration

    Internally, ion-ngx-storage operates in the following manner:

    1. Register StorageEffects and HydrateEffects.
    2. Dispatch Read from HydrateEffects.
    3. Read state from storage and dispatch ReadResult.
    4. Merge the result into the application state via meta-reducer.
    5. If { hydrated: true } then dispatch ReadSuccess.

    ReadSuccess Action

    ion-ngx-storage makes the ReadSuccess action public for use in NgRx effects.

    import { ReadSuccess } from '@d4h/ion-ngx-storage';
    
    @Injectable()
    export class AppEffects {
      // Keep up splash screen until after hydration.
      init$: Observable<Action> = createEffect(() => this.actions$.pipe(
          ofType(ReadSuccess),
          tap(() => {
            this.platform.ready().then(() => {
              this.statusBar.styleLightContent();
              this.splashScreen.hide();
            });
          })
        ),
        { dispatch: false }
      );
    
      constructor(/* ... */) {}
    }

    Inject Configuration

    The public STORAGE_CONFIG token allows injection of the configuration in cases of module composition.

    import { STORAGE_CONFIG, StorageConfig, StorageModule } from '@d4h/ion-ngx-storage';
    
    @NgModule({
      imports: [
        StorageModule
      ]
    })
    export class AppFeatureModule {
      static forFeature(config: FeatureConfig): ModuleWithProviders {
        return {
          ngModule: AppFeatureModule,
          providers: [
            { provide: STORAGE_CONFIG, useValue: config.storage }
          ]
        };
      }
    }

    Selecting Storage Status

    ion-ngx-storage makes StorageState available for cases where you need to select or extend the state:

    import { StorageState } from '@d4h/ion-ngx-storage';
    
    export interface AppState extends StorageState {
      // ...
    }

    After this you can employ the getHydrated and getStorageState selectors.

    Defer Store Access

    Although ion-ngx-storage hydrates data from storage once NgRx Effects dispatches ROOT_EFFECTS_INIT, the asynchronous nature of Angular and NgRx make it likely your application will attempts to read from the state it is ready. Applications which rely on the NgRx store to determine i.e. authentication status must be modified in a way which defers assessment until after hydration.

    In both cases below:

    1. filter(Boolean) leads to only truthy values emitting.
    2. Once this happens, switchMap replaces the prior observable with a new one that contains the actual assessment of authentication status.

    AccountFacade

    import { StorageFacade } from '@d4h/ion-ngx-storage';
    
    @Injectable({ providedIn: 'root' })
    export class AccountFacade {
      readonly authenticated$: Observable<boolean> = this.storage.hydrated$.pipe(
        filter(Boolean),
        switchMap(() => this.store.select(getAuthenticated))
      );
    
      constructor(
        private readonly storage: StorageFacade,
        private readonly store: Store<AppState>
      ) {}
    }

    AuthenticatedGuard

    import { AccountFacade } from '@app/store/account';
    
    @Injectable({ providedIn: 'root' })
    export class AuthenticatedGuard implements CanActivate {
      private readonly authenticated$: Observable<boolean>;
    
      constructor(
        private readonly accounts: AccountFacade,
        private readonly router: Router
        ) {
          this.authenticated$ = this.store.pipe(
            select(getHydrated),
            filter(Boolean),
            switchMap(() => this.store.select(getAuthentication))
          );
        }
    
      canActivate(): Observable<boolean | UrlTree> {
        return this.authenticated$.pipe(
          map((authenticated: boolean): boolean | UrlTree => {
            return authenticated || this.router.parseUrl('/login');
          })
        );
      }
    }

    Logout/Reinitialization

    Many applications have some kind of logout action which resets the application to its in initial state. In these cases ion-ngx-storage resets to { hydrated: false }, meaning it will no longer write device state to storage. In these cases you have to dispatch one Clear or Read:

    • Clear: Wipe the stored application state and triggers Read with an initial empty value.
    • Read: Reads the logged-out state and triggers reducer setting { hydrated: true }.

    The difference in practice is whether you want to remove all content stored on the device.

    import { Read } from '@d4h/ion-ngx-storage';
    
    class LoginEffects {
      logout$: Observable<Action> = createEffect(() => this.actions$.pipe(
        ofType(Logout),
        switchMap(() => [
          Read(),
          Navigate({ path: ['/login', 'username'] })
        ])
      ));
    }

    Support and Feedback

    Feel free to email support@d4h.org, open an issue or tweet @d4h.

    License

    Copyright (C) 2019 D4H

    Licensed under the MIT license.

    Install

    npm i @d4h/ion-ngx-storage

    DownloadsWeekly Downloads

    7

    Version

    2.3.0

    License

    MIT

    Unpacked Size

    316 kB

    Total Files

    48

    Last publish

    Collaborators

    • hannesvdvreken
    • bhalash