为 Angular Router Guard 处理多个 Observable
Handle multiple Observables for Angular Router Guard
我是 RxJS 的新手,但似乎符合我的需要。
I am wondering if it's possible to retrieve an Observable
that listen two BehaviorSubject
.
首先我使用 Angular 10 !
我正在使用
- 调用我的组件的服务创建检索用户数据的承诺
- 特定路线上的守卫,这些路线也使用以前的服务来确定访问权限。
为了更好地理解这里是我的配置:
// auth.guard.ts
import { Injectable } from '@angular/core';
import {... } from '@angular/router';
import { from, Observable, Subscription } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate, CanLoad, CanActivateChild {
constructor(private auth: AuthService) { }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean | UrlTree> {
return from(this.auth.canActivate());
}
}
//app-routing.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SecuredComponent } from './pages/secured/secured.component';
import { AuthGuard } from './auth.guard';
const routes: Routes = [
// other paths
{
path: 'mes-formations',
component: SecuredComponent,
canActivate: [AuthGuard]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
//auth.service.ts
import { Injectable, OnDestroy } from '@angular/core';
import { BehaviorSubject} from 'rxjs';
import { UrlTree } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthService implements OnDestroy {
private userOk$ = new BehaviorSubject(false);
private isLoading$ = new BehaviorSubject(false);
constructor(args) {
this.authenticate();
}
async authenticate(): Promise<boolean | UrlTree> {
// set isLoading$ to true till user request ends
// fetch user and set userOk$ to true if succeed
}
async canActivate(): Observable<boolean | UrlTree> {
// return true if isLoading is false AND userOk$ true
// instead redirect outside app
}
}
我的目标是根据以下条件给出 AuthGuard
的答案:
- 如果
isLoading
为真 -> 等待
- 如果
isLoading
为假且 userOk
为真 -> 为真
- 如果
isLoading
为假且 userOk
为假 -> 做其他事情
怎样才能做到这一点?
谢谢大家!
尝试利用 combineLatest
、filter
和 map
。
您可能希望从 isLoading$
开始 true
而不是 false
。
canActivate(): Observable<boolean> {
return combineLatest(
this.isLoading$,
this.userOk$,
).pipe(
filter(([isLoading, userOk]) => !isLoading), // wait until isLoading is false (filter emissions while isLoading is true)
map(([isLoading, userOk) => {
if (userOk) { // isLoading is false and userOk is true
return true;
} else { // isLoading is false and userOk is false
// do something else (do whatever else you want to do and return false)
return false;
}
})
);
}
我是 RxJS 的新手,但似乎符合我的需要。
I am wondering if it's possible to retrieve an
Observable
that listen twoBehaviorSubject
.
首先我使用 Angular 10 !
我正在使用
- 调用我的组件的服务创建检索用户数据的承诺
- 特定路线上的守卫,这些路线也使用以前的服务来确定访问权限。
为了更好地理解这里是我的配置:
// auth.guard.ts
import { Injectable } from '@angular/core';
import {... } from '@angular/router';
import { from, Observable, Subscription } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root',
})
export class AuthGuard implements CanActivate, CanLoad, CanActivateChild {
constructor(private auth: AuthService) { }
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean | UrlTree> {
return from(this.auth.canActivate());
}
}
//app-routing.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SecuredComponent } from './pages/secured/secured.component';
import { AuthGuard } from './auth.guard';
const routes: Routes = [
// other paths
{
path: 'mes-formations',
component: SecuredComponent,
canActivate: [AuthGuard]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
//auth.service.ts
import { Injectable, OnDestroy } from '@angular/core';
import { BehaviorSubject} from 'rxjs';
import { UrlTree } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthService implements OnDestroy {
private userOk$ = new BehaviorSubject(false);
private isLoading$ = new BehaviorSubject(false);
constructor(args) {
this.authenticate();
}
async authenticate(): Promise<boolean | UrlTree> {
// set isLoading$ to true till user request ends
// fetch user and set userOk$ to true if succeed
}
async canActivate(): Observable<boolean | UrlTree> {
// return true if isLoading is false AND userOk$ true
// instead redirect outside app
}
}
我的目标是根据以下条件给出 AuthGuard
的答案:
- 如果
isLoading
为真 -> 等待 - 如果
isLoading
为假且userOk
为真 -> 为真 - 如果
isLoading
为假且userOk
为假 -> 做其他事情
怎样才能做到这一点? 谢谢大家!
尝试利用 combineLatest
、filter
和 map
。
您可能希望从 isLoading$
开始 true
而不是 false
。
canActivate(): Observable<boolean> {
return combineLatest(
this.isLoading$,
this.userOk$,
).pipe(
filter(([isLoading, userOk]) => !isLoading), // wait until isLoading is false (filter emissions while isLoading is true)
map(([isLoading, userOk) => {
if (userOk) { // isLoading is false and userOk is true
return true;
} else { // isLoading is false and userOk is false
// do something else (do whatever else you want to do and return false)
return false;
}
})
);
}