Search code examples
angularrxjsbehaviorsubject

How to force dataservice with BehaviourSubject Angular to return last value set with next()


I am writing Angular Guards form my application. After a user logs in my AuthService I change the value of a BehaviourSubject variable in my userService using the next(). In my GuardService, I want to get the latest value from the variable but I always get the initial value.

userService

export class UserService {

private isAdmin = new BehaviorSubject<boolean>(true);
isCurrentUserAdmin = this.isAdmin.asObservable();

changeAdminRole(isAdmin: boolean) {
    // change the BehaviourSubject value
    this.isAdmin.next(isAdmin);
  }
}

AdminGuard

export class AdminGuard implements CanActivate {

  constructor(private userService: UserService) { }

  canActivate() {
    this.userService.isCurrentUserAdmin
      .subscribe((response: boolean) => {
        console.log('working here', response);
        if(response) return true;
      });

    return false;
  }
}

appModule

app.module.ts
imports: [
    BrowserModule,
    AppRoutingModule,
    BsDropdownModule.forRoot(),
    RouterModule.forRoot([
      {path: '', component: HomeComponent},
      {path: 'products', component: ProductsListComponent, canActivate: [AuthGuard, AdminGuard]},
      {path: 'shopping-cart', component: ShoppingCartComponent},
      {path: 'my-orders', component: MyOrdersComponent, canActivate: [AuthGuard, AdminGuard]},
      {path: 'check-out', component: CheckOutComponent, canActivate: [AuthGuard, AdminGuard]},
      {path: 'order-success', component: OrderSuccessComponent, canActivate: [AuthGuard, AdminGuard]},
      {path: 'login', component: LoginComponent},
      {path: 'admin/products', component: AdminProductsListComponent, canActivate: [AuthGuard, AdminGuard]},
      {path: 'admin/orders', component: AdminOrdersListComponent, canActivate: [AuthGuard, AdminGuard]},
      {path: '**', component: HomeComponent}
    ])
],
  providers: [AuthService, UserService, AuthGuard, AdminGuard]

I expect the reponse in the observable of my AdminGuard when I navigate to the route I want to protect to have the latest value set in the UserService.changeAdminRole() when called from my AuthService but I am always getting null.


Solution

  • You are trying to return true from subscribe not from the guard. Your guard always returns false. CanActivate can return also observable which eventually resolves to boolean which perfectly fits your situation:

    canActivate() {
      return this.userService.isCurrentUserAdmin;
    }