首页 文章

如何使用Observable进行组件间通信

提问于
浏览
0

我使用来自Rxjs的Observables和Subjects来在两个组件之间进行通信,这是服务部分:

import {
  Injectable,
  EventEmitter,
  Output
} from '@angular/core';
import {
  HttpClientModule,
  HttpClient
} from '@angular/common/http';

import {
  Observable
} from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import {
  Subject
} from 'rxjs/Subject';


import {
  AppConstants
} from './../config/constants';

@Injectable()

export class GlobalService {
  private subject = new Subject < any > ();
  @Output() LoggedIn: EventEmitter < any > = new EventEmitter();
  mfaData: any;
  constructor(private http: HttpClient) {

  }

  validateCreds(postData, institutionId, customerId) {
    return this.http.post(AppConstants.baseUrl + AppConstants.serverRoutes.validateCreds + institutionId + '/' + customerId, postData)
      .subscribe(response => {
        console.log(response);
        if (response['status'] == 203) {
          this.mfaData = response['body'].questions;
          if (this.mfaData[0].choices || this.mfaData[0].imageChoices) {
            console.log('hey there');
            this.subject.next({
              mfaData: JSON.stringify(this.mfaData)
            });
           
          }
        }
      })
  }


  

  refreshHeaders(): Observable < any > {
    return this.subject.asObservable();
  }





}

我从另一个组件的构造函数调用订阅者的片段是:

import {
  Subscription
} from 'rxjs/Subscription';
import {
  GlobalService
} from '../../../providers/global.serivce';

export class MfaChallengeComponent implements OnInit {
  subscription: Subscription;
  constructor(private activatedRoute: ActivatedRoute, private bankService: BanksService, private globalService: GlobalService) {
    this.subscription = this.globalService.refreshHeaders().subscribe(message => {
      console.log(message);
    });
  }
}

但是当我从后端收到数据时,我调用了主题的下一个方法,并在另一个组件的构造函数中再次调用它 . 它不起作用,而我看到它的工作实例 . 该服务已在全球注入 .

1 回答

  • 4

    我担心你误解了RxJS的一些核心概念 . 在RxJS中,受试者是热的可观察者 . 无论是否有人在听,热的观察者都会发出事件 . (查看此文章了解更多信息https://blog.thoughtram.io/angular/2016/06/16/cold-vs-hot-observables.html) .

    因此,假设在您的服务中,您执行后端呼叫,您可以通过主题“管道”该呼叫的结果 . 稍后在代码中,您的组件已启动,构造函数已执行,您开始收听主题 . 不幸的是,你通过这个主题的事件已经过去了 .

    要解决此问题,您可以使用ReplaySubject(1)更改主题 . 如果我没有弄错,那应该解决问题 .

    但是,您的代码还有其他一些问题 . 你通过一个主题管道结果的事实在这里是不必要的 . 如果我查看你的代码,我想你想做一次后端调用,然后缓存结果 . 这个叫做 shareReplay 的特定运算符 . 使用它你的代码看起来像这样:

    export class GlobalService {
      cachedObservable$;
      @Output() LoggedIn: EventEmitter < any > = new EventEmitter();
      mfaData: any;
      constructor(private http: HttpClient) {
      }
    
      validateCreds(postData, institutionId, customerId) {
        this.cachedObservable$ = this.http.post(AppConstants.baseUrl + AppConstants.serverRoutes.validateCreds + institutionId + '/' + customerId, postData)
          .map(response => {
            if (response['status'] == 203) {
              this.mfaData = response['body'].questions;
              if (this.mfaData[0].choices || this.mfaData[0].imageChoices) {
                return {
                  mfaData: JSON.stringify(this.mfaData)
                };
              }
            }
          })
          .shareReplay(1);
      }
    
      refreshHeaders(): Observable < any > {
        return this.cachedObservable$;
      }
    }
    

    您正在创建一个将被执行一次的observable,之后的结果将被缓存 . 您应尽量避免在服务和主题中使用订阅 . 要了解有关 shareReplay 的更多信息,请查看关于RxJS中多播运营商的博文,我写道:https://blog.kwintenp.com/multicasting-operators-in-rxjs

相关问题