我无法订阅 angular 13 中可观察到的 mergeMap

I can not subscribe on mergeMap observable in angular 13

我想实现一个基于 angular 中角色的连接场景。当用户在填写表单(用户名 - 密码)后单击 CONNEXION 按钮时,会调用两个 API url 来提供相同的连接,我正在使用 angular 13 作为前端。在后端,我有两个端点(资源请求 url )来服务连接过程。第一个资源

this.http.post(${environment.baseUrlUserSecurity}/users/login, data, Option)

提供用于身份验证的令牌和第二个资源

this.http.get(${environment.baseUrlUserSecurity}/prsnls, this.userId)

必须根据令牌中第一个 API 调用提供的 userId 找到用户的角色。用邮递员测试时一切正常。但是我正在努力用 angular 在前端实现连接过程,这是我到目前为止所做的:

//调用 2 API URL 的登录方法

login(data){
      const Option ={ headers: new HttpHeaders({'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json',"USER_CODE":data.USER_CODE})};
      this.http.post<any>(`${environment.baseUrlUserSecurity}/users/login`, data, Option)
      .pipe(
        map(value => value[0]))
      .subscribe( value => {
        this.userId = value.result.userId;
        this.http.get(`${environment.baseUrlUserSecurity}/prsnls`, this.userId)
        .subscribe( user => {
          this.user = user;
          localStorage.setItem('currentUser', JSON.stringify(user));
              this.currentUserSubject.next(user);
              return user;
        });
      })
    }

//按下按钮时的提交动作

onSubmit(){
    const data = this.loginForm.getRawValue();
    this.submitted = true;
    localStorage.setItem('USER_CODE',data.USER_CODE);
    this.loading = true;
    this.isLoading = true;
    of(null)
      .pipe(
        delay(2000),
        first()
      )
      .subscribe(() => {

        this.isLoading = false;
        this.authService.login(data).subscribe(
            (res:any)=>{
              if (res.code==200){
                  localStorage.setItem('token',res.result.token);
                  localStorage.setItem("infos", JSON.stringify(res.result.roleIds));
                  localStorage.setItem("prsl", res.result.userId);
                  //this.getUserInfos(res.result.userId);
                  this.router.navigate(['/dashboard']);
              }

              this.rMessage = '';

            },
              error => {
                  this.rMessage = 'bError';
                  this.loading = false;
              }
          );
      });


  }

问题是编辑器说'subscribe()'属性在onsubmit()函数内的类型void上不存在this.authService.login(data).subscribe() 而且我不明白为什么我不能订阅那个 observable。如果有人能提供帮助,我将不胜感激,因为我不知道如何解决这个问题并让编辑器没有错误。提前致谢。

记住:“您的服务 return observables,您订阅组件”

每次您在服务中写“订阅”时,您都在犯错误 (*)

好吧,你需要 return 一个基于另一个的可观察对象,所以你需要使用 switchMap rxjs 运算符。 switchMap 总是挡路

observable1(data).pipe(switchMap(res=>{
   //here res is the response of the observable1(data)
   //you return another observable based in res
   return observable2(res) 
})

您的登录

login(data){
      const Option ={ headers: new HttpHeaders({'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json',"USER_CODE":data.USER_CODE})};
      
      //see that you "return" an observable
      return this.http.post<any>(`${environment.baseUrlUserSecurity}/users/login`, data, Option)
      .pipe(
       switchMap(value=>{
          const userId=value[0].result.userId
          return this.http.get(`${environment.baseUrlUserSecurity}/prsnls`, userId)

       })

现在您可以订阅了

onSubmit(){
    const data = this.loginForm.getRawValue();
    this.submitted = true;
    this.authService.login(data).subscribe(
            (res:any)=>{
              if (res.code==200){
                  localStorage.setItem('token',res.result.token);
                  localStorage.setItem("infos", JSON.stringify(res.result.roleIds));
                  localStorage.setItem("prsl", res.result.userId);
                  //this.getUserInfos(res.result.userId);
                  this.router.navigate(['/dashboard']);
              }

              this.rMessage = '';

            },
              error => {
                  this.rMessage = 'bError';
                  this.loading = false;
              }
          );
      }); 

(*)好吧,你可以在你的服务中加入一些像

subject=new Subject<any>()
getData(){
   this.httpClient.get(...).subscribe(res=>{
       this.subject.next(res)
   })
}

然后您订阅“主题”并调用函数

this.authService.subject.subscribe(res=>{
   ...
})
this.authService.getData();

但它适用于一些“特殊情况”

Update 有时,我们还需要内部 Observable 的数据,我们还需要使用另一个 rxjs 运算符的第一个 observable 的数据 map

我们可以做到

   observable1(data).pipe(switchMap(respose1=>{
       return observable2(response1).pipe(map(response=>(
         {response1:response1,response2:response2}
       )))
    })

我们有一个具有两个属性的对象:response1 和 response2

我们也可以使用展开运算符进行映射

   observable1(data).pipe(switchMap(respose1=>{
       return observable2(response1).pipe(map(response=>(
         {...response1,...response2}
       )))
    })

然后我们得到一个具有 response1 和 response2 的所有属性的唯一对象

您需要 return Observablelogin 方法。

如果您订阅并且 return 那么将会 returning Subcription type.So in-order 到 return Observable 并且操作结果并在响应出现后做一些事情你必须使用 pipe.

我改变了你的登录方法如下

  login(data): Observable<any> {
    const Option = {
      headers: new HttpHeaders({
        'Access-Control-Allow-Origin': '*',
        'Content-Type': 'application/json',
        USER_CODE: data.USER_CODE,
      }),
    };
    return this.http
      .post<any>('${environment.baseUrlUserSecurity}/users/login', data, Option)
      .pipe(
        map((value) => value[0]),
        tap((value) => (this.userId = value.result.userId)),
        switchMap((value) =>
          this.http
            .get<User>('${environment.baseUrlUserSecurity}/prsnls', this.userId)
            .pipe(
              tap((user:User) => {
                this.user = user;
                localStorage.setItem('currentUser', JSON.stringify(user));
                this.currentUserSubject.next(user);
              }),
              map((user) => ({ ...user, ...value }))
            )
        )
      );
  }