如何在Angular 5.x中将异步可观察数据从服务返回到组件?

时间:2018-01-16 20:03:00

标签: angular asynchronous service components observable

我有一个组件(我们称之为CA),它创建了许多组件(CB)。 每个组件CB从服务类调用相同的函数。

此函数创建并返回一个Observable。 在这个Observable的回调函数中(让它称之为O1),它订阅了另一个Observable(O2),它是服务类的成员

只要从WebSocket连接接收数据,Obseable O2就会将数据推送给观察者。

在Observable O1中,当它从O2接收数据时,会将此数据推送给其观察者。

我的问题是,我的组件CB(正如我之前所说,订阅此Observable(O1)不会收到O1发送的数据。

当调试O1回调代码时,我可以在O1从O2接收数据时中断。然后,它执行" observer.next(dataReceivedFromO2)"。 但订阅者(每个组件C2中有1个)没有收到任何数据,我也不明白为什么。

任何人都可以帮我解决这个问题吗?提前感谢您的帮助

Node version: 8.4.0

Here are my dependencies:
  "dependencies": {
    "@angular/animations": "5.2.0",
    "@angular/cdk": "5.0.4",
    "@angular/common": "5.2.0",
    "@angular/compiler": "5.2.0",
    "@angular/core": "5.2.0",
    "@angular/flex-layout": "2.0.0-beta.12",
    "@angular/forms": "5.2.0",
    "@angular/http": "5.2.0",
    "@angular/material": "5.0.4",
    "@angular/platform-browser": "5.2.0",
    "@angular/platform-browser-dynamic": "5.2.0",
    "@angular/router": "5.2.0",
    "bootstrap": "4.0.0-beta",
    "core-js": "2.5.3",
    "font-awesome": "4.7.0",
    "hammerjs": "2.0.8",
    "material-design-icons": "3.0.1",
    "rxjs": "5.5.6",
    "typedoc": "0.9.0",
    "zone.js": "0.8.20"
  },
  "devDependencies": {
    "@angular/cli": "1.6.4",
    "@angular/compiler-cli": "5.2.0",
    "@angular/language-service": "5.2.0",
    "@types/jasmine": "2.8.3",
    "@types/jasminewd2": "2.0.3",
    "@types/node": "9.3.0",
    "codelyzer": "4.0.2",
    "jasmine-core": "2.8.0",
    "jasmine-spec-reporter": "4.2.1",
    "karma": "2.0.0",
    "karma-chrome-launcher": "2.2.0",
    "karma-cli": "1.0.1",
    "karma-coverage-istanbul-reporter": "1.3.3",
    "karma-firefox-launcher": "1.1.0",
    "karma-jasmine": "1.1.1",
    "karma-jasmine-html-reporter": "0.2.2",
    "karma-json-reporter": "1.2.1",
    "protractor": "5.2.2",
    "ts-node": "4.1.0",
    "tslint": "5.9.1",
    "typescript": "2.6.2"
  }

这是我的服务:

注意:在这里,O2被命名为" liveObservable"。 FunctiongetLiveResumeData()将一个Observable(在我们的Context中也称为O1)返回给调用它的每个组件。

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { WebsocketService } from './websocket.service';

import { IResumeReadings } from './../types/resume.readings';

@Injectable()
export class ResumeLiveService {

  resumeWebSocket: WebSocket;
  started = false;
  counter = 0;
  liveObservable: Observable<IResumeReadings[]>;

  constructor(private websocketService: WebsocketService) {
    this.openService(this.websocketService);

    if (!this.started) {
      this.resumeWebSocket.onopen = () => {
        this.resumeWebSocket.send('get_resume_data');
        this.started = true;
      };
    }

    // Here is my Observable O2
    this.liveObservable = Observable.create((observer) => {
      // When data comes from WebSocket, data are sent to observer
      this.resumeWebSocket.onmessage = (message: any) => {
        const bodyAsJson: IResumeReadings[] = JSON.parse(message.data);
        // Sending data to observer
        observer.next(bodyAsJson);
      };

      this.resumeWebSocket.onerror = (error) => {
        observer.error(error);
      };

      return () => {
        // If all components (C2) have unregistered from their respective Observable,
        // the service sends over websocket a message to stop sending data
        if (this.started && this.counter === 0) {
          this.resumeWebSocket.send('stop_resume_data');
          this.started = false;
        }
      };
    });
  }

  // Function that is called by each Component (C2)
  getLiveResumeData(id ?: number): Observable<IResumeReadings[]> {
    if (!this.started) {
      this.counter = 0;
      if (this.resumeWebSocket.readyState === this.resumeWebSocket.OPEN) {
        this.resumeWebSocket.send('get_resume_data');
        this.started = true;
      } else {
        this.resumeWebSocket.onopen = () => {
          this.resumeWebSocket.send('get_resume_data');
          this.started = true;
        };
      }
    }
    this.counter += 1;

    // We create and return an Observable (O1) which push data to observers when
    // it receives data from liveObservable (O2)
    return Observable.create((observerTest) => {
      const subs = this.liveObservable.subscribe((data) => {
        observerTest.next(data);
      }, (error) => {
        observerTest.error(error);
      });

      return () => {
        subs.unsubscribe();
        this.counter -= 1;
      };
    });

这是我的组件(C2)

export class MeasurementCardComponent implements OnInit, OnDestroy {

  @Input()
  measurementInfo: IMeasurementInfo;
  @Input()
  formID: string;
  data: Observable<IResumeReadings[]>;
  alarmStatus: AlarmStatus;
  liveResumeSub: Subscription;
  constructor(private utilsService: UtilsService,
              private resumeLiveService: ResumeLiveService) { }

  ngOnInit() {
    // Storing Observable (O1) from service 
    this.data = this.resumeLiveService.getLiveResumeData(this.measurementInfo.id);
    // We subscribe to this Observable
    this.liveResumeSub = this.data.subscribe(
      (readings) => {
      //  ==============> !!!!!!!!!!!     NEVER COMES OR BREAKS HERE      :-(   !!!!!!!!!!!!!!!!!!   <==================
        if (readings[0].limits) {
          for (const limit of readings[0].limits) {
            this.formControls[limit.name] = this.formBuilder.control(limit.value, [Validators.required]);
          }
        }

        const previousAlarmStatus = this.alarmStatus;
        this.alarmStatus = this.utilsService.measurementStyleAlarm(readings[0]);

        if (this.alarmStatus !== previousAlarmStatus) {
          this.setCardAlarmStyle();
        }
      },
      (err: HttpErrorResponse) => {
        if (err.error instanceof Error) {
           // A client-side or network error occurred.
          console.log(`An error occured while getting resume readings for cards: ${err.error.message}`);
        } else {
          // The backend returned an unsuccessful response code.
          // The response body may contain clues as to what went wrong
          console.log(`While getting resume readings for cards, Web server returned code ${err.status},` +
                      `message was: ${err.message}`);
        }
      },
    () => {
      console.log('complete');
    });
  }

0 个答案:

没有答案