npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@d4h/ion-ngx-storage

v2.3.0

Published

Synchronize an NgRx state to device storage.

Downloads

35

Readme

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 [email protected], open an issue or tweet @d4h.

License

Copyright (C) 2019 D4H

Licensed under the MIT license.