5

I'm trying to create an "auth app" with redux(ngrx) and I'm trying to use my app state in the secret guard. Here you can see my github: https://github.com/tamasfoldi/ngrx-auth/tree/router This is how my guard looks like:

@Injectable()
export class SecretGuard implements CanActivate {
  constructor(private store: Store<AppState>, private router: Router) {
  }
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.store.let(getLoginState())
      .map(state$ => state$.isLoggedIn)
  }
}

It returns with the isLoggedIn attribute which should be OK because router resolves promises and observable, but the router block it when I navigate to the secret part. Here are my routes:

export const appRoutes: Routes = [
  {
    path: '',
    redirectTo: 'auth',
    pathMatch: 'full'
  },
  {
    path: 'auth',
    children: [
      { path: '', redirectTo: 'login', pathMatch: 'full' },
      { path: 'login', component: LoginComponent },
      { path: 'register', component: RegisterComponent }
    ]
  },
  {
    path: 'secret',
    canActivate: [SecretGuard],
    children: [
      { path: '', redirectTo: 'default', pathMatch: 'full' },
      { path: 'default', component: DefaultSecretComponent }
    ]
  }
];

In redux I receive the init state so I also have tried to skip the first emission in my observable, but it neither works. Here is the skipping code:

@Injectable()
export class SecretGuard implements CanActivate {
  constructor(private store: Store<AppState>, private router: Router) {
  }
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.store.let(getLoginState())
      .skip(1)
      .map(state$ => state$.isLoggedIn)
  }
}

If I use my AuthService's auth function it is working properly, but that solution is not "redux-like". Can you help me with it how to make it work with ngrx? Or I'm not able to use my appstate in guards?

bucicimaci
  • 1,261
  • 1
  • 9
  • 17

1 Answers1

4

You can synchronously get value from store, don't need to "stream everything" (:

https://github.com/ngrx/store#getstate-getvalue-and-value

import 'rxjs/add/operator/take';

function getState(store: Store<State>): State {
    let state: State;
    store.take(1).subscribe(s => state = s);
    return state;
}

@Injectable()
export class SecretGuard implements CanActivate {
  constructor(private store: Store<AppState>, private router: Router) { }

  canActivate():boolean {
    return getState(this.store).login.isLoggedIn;
  }
}
Sasxa
  • 40,334
  • 16
  • 88
  • 102
  • Thanks it is working, but if I add some error handling logic to it (redirect to auth if the guard fails) I get redirected to the auth page. I think this is because the initial state's isLoggedIn property is false. If I skip(1) it is OK on reloads, but not working when trying to navigate from the navbar, because it skips every first. Do you have some idea how to solve this? – bucicimaci Oct 04 '16 at 15:55
  • It is working if I use debounceTime but not sure if that is the best solution – bucicimaci Oct 04 '16 at 16:15
  • 2
    I didn't have this problem because I decided early to have two reducers - `auth` and `user`. I use `auth` just for true/false/pending and `user` for user profile data, then use `auth` in guards, and `user` in components for redirects. It's somewhat more work during login/logout - I'm dispatching `LoginUserAction` AND `LoginAuthAction` but easier to handle later. I expect it will be usefull for lazy-loading too, I can pack `auth` in **AppModule** and 'user' in **AdminModule**... – Sasxa Oct 04 '16 at 16:16
  • Hm thanks. I will give it a try. Sounds better. What is the initial value for the `auth`, pending or false? If you dont have initial value problem I think pending and you dont redirect till it is not "stable"(true of false). Am I right? – bucicimaci Oct 04 '16 at 16:24
  • I'm actually use `null`, `true`, `false` and `"pending"` and `setTimeout` to get it to the **stable** state (: A bit weird setup (might even change it), but works for now. Something like [this code](http://plnkr.co/edit/9IQHqNr2iLFO2m1ta4KF). – Sasxa Oct 04 '16 at 16:36
  • Thanks I will try it, and I've accepted your answer because solved the original problem. – bucicimaci Oct 04 '16 at 16:59