结合Angular中的RxJS Observable

时间:2018-12-03 22:56:25

标签: angular firebase rxjs

问题:如果firebase-auth没有用户登录,我需要转到登录页面,如果有用户登录,我需要转到备用页面。

要实现此目的,它将在构造函数服务中调用一个函数。

private isLoginRequired() {
// Firebase auth service observable
let authSub = this.afAuth.authState;

// Current route service observable
let routeSub = this.activatedRoute.url;

//Alternate App Page
//this.router.navigate(["tool/event-management/events"]);

//Login Page
//this.router.navigate(["tool/event-management/login"]);

}

现在,我需要以一种这样的方式来组合这些可观察物:如果其中任何一个的值发生变化,我都可以通过一次订阅来收集这两个可观察物的当前值。

something.subscribe(observableSnapshots => {
  let snapshot_auth = observableSnapshots[0];
  let snapshot_route = observableSnapshots[1];

  if(condition<snapshot_route, snapshot_auth>){
    // do anything positive
  }
  else{
    // do anything negative
  }
});

我知道可以通过嵌套订阅来实现,但这肯定不是一种有效的方式。

我也尝试过mergeMap但无法达到要求,这是代码段(无效)

routeSub
      .pipe(mergeMap(event1 => authSub.pipe(map(event2 => "test"))))
      .subscribe(result => {
        console.log(result);
      });

请告诉我一个更好的出路。预先感谢。

  

依赖关系:“ rxjs”:“〜6.3.3”

3 个答案:

答案 0 :(得分:2)

我会使用路由防护器来执行您所描述的操作:

这是Jeff Delaney的AngularFirebase网站上经过稍微修改的代码段,请参见:https://angularfirebase.com/lessons/google-user-auth-with-firestore-custom-data/

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { AngularFireAuth } from '@angular/fire/auth';
import { Observable } from 'rxjs';
import { tap, map, take } from 'rxjs/operators';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private auth: AngularFireAuth, private router: Router)
{}


  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> {

      return this.auth.authState.pipe()
           take(1),
           map(user => !!user),
           tap(loggedIn => {
             if (!loggedIn) {
               console.log('access denied')
               this.router.navigate(['/login']);
             }
         })
    )
  }
}

以下是将防护添加到路由器的方法:

const routes: Routes = [
  { path: '**', component: SomeComponent, canActivate: [AuthGuard]},
]

您可以按照我在此处所做的操作导入在守卫中可观察到的Firebase auth,但是,最好在自己的服务imo中添加它。检查指向AngularFirebase的链接,以查看执行此操作的服务的代码。

如果您要在注销后将用户拒之门外,请在组件中尝试以下代码:

export class SomeComponent implements OnInit {
        constructor(private auth: AngularFireAuth, private router: Router)
{
    ngOnInit(): void {
        this.auth.authState.subscribe((authObj) => {
            if(authObj === null){
                this.router.navigate(['/login']);
            }
        })
    }
}

答案 1 :(得分:1)

我不确定您在做什么,但听起来combineLatest可能有用

// Firebase auth service observable
let authSub = this.afAuth.authState;

// Current route service observable
let routeSub = this.activatedRoute.url;

const sub = combineLatest(authSub, routeSub)
   .pipe(
     tap(([authResult, routeResult]) => {
         // the above uses array param destructuring, so we have two variables
         if(authResult === something and routeResult === something){
            //Do Something
         } 
         else {
           // do something else
         }
     })
   )
   .subscribe();

activatedRoute.urlobservable of a BehaviorSubject,因此在您订阅时它将为您提供最新的结果,我认为Firebase Auth服务也是如此,但是您必须对其进行测试< / p>

其中可能存在语法错误,只需直接输入即可,但这是您的基本combineLatest

答案 2 :(得分:0)

最后,我在@Drenai帮助下找到了此代码段。

private isLoginRequired():void {
let authSub: Observable<firebase.User> = this.afAuth.authState;
let routeSub: Observable<any> = this.router.events;

combineLatest(authSub, routeSub).subscribe(
  ([authSubSnap, routeSubSnap]):void => {
    let islogin: boolean = !!authSubSnap;
    let current_url: string = routeSubSnap.url;

    if (!islogin) {
      this.router.navigate([this.loginPageURL]);
    } else if (current_url === this.loginPageURL && islogin) {
      this.router.navigate(["tool/event-management/events"]);
    }
  }
);
}