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.
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] },