Search code examples
angularngxs

How to trigger NgxsOnInit?


I want to trigger an action when the user first visit my site. What's the best way in doing this with ngxs? I found out there's this thing called NgxsOnInit but I don't know how it is triggered.


Solution

  • the NgxsOnInit is an interface that you implement in your state class.

    a good use for this is dispatch actions when the state loads the first time.

    // auth.actions.ts
    export class CheckSession() {
      static readonly type = 'auth/check-session';
    }
    
    
    // auth.state.ts
    import { State, Action, NgxsOnInit } from '@ngxs/store';
    
    export interface AuthStateModel {
      token: string;
    }
    
    @State<AuthStateModel>({
      name: 'auth',
      defaults: {
        token: null
      }
    })
    export class AuthState implements NgxsOnInit {
    
      ngxsOnInit(ctx: StateContext<AuthStateModel>) {
        ctx.dispatch(new CheckSession());
      }
    
      @Action(CheckSession)
      checkSession(ctx: StateContext<AuthStateModel>, action: CheckSession) {
        ...
      }
    }
    

    But if you need to get some info based on the url, it's better to create a route guard that dispatches the action and then uses store.selectOnce to retrieve the value you need from the state.

    import { Injectable } from '@angular/core';
    import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot } from '@angular/router';
    import { Store, ofAction } from '@ngxs/store';
    import { Observable, of } from 'rxjs';
    import { tap, map, catchError } from 'rxjs/operators';
    
    import { GetProject } from './project.action';
    import { ProjectState } from './project.state';
    
    @Injectable({
      providedIn: 'root'
    })
    export class ProjectGuard implements CanActivate {
    
      constructor(private store: Store) {}
    
      canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
        const projectId = route.paramMap.get('projectId');
    
        // we call the store which downloads the project, we then wait for the action handler to return the project
        return this.store.dispatch(new GetProject(projectId)).pipe(
          // we convert the project to a boolean if it succeeded
          map(project => !!project),
    
          // we catch if the GetProject action failed, here we could redirect if we needed
          catchError(error => {
            return of(false);
          })
        );
      }
    }
    

    // app routes

    { path: 'project/:projectId', loadChildren: './project#ProjectModule', canActivate: [ProjectGuard] },