简体   繁体   English

Angular2共享可观察

[英]Angular2 shared observable

Doing some experimentation with Angular2 and curious about how to solve a situation where a service exposes a shared observable. 对Angular2进行了一些试验,并对如何解决服务公开共享的可观察对象的情况感到好奇。 Where one component is responsible for getting the data and another is responsible for displaying the data. 其中一个组件负责获取数据,另一个组件负责显示数据。 Here is some code: 这是一些代码:

The common HttpService responsible for getting the data 负责获取数据的通用HttpService

import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

@Injectable()
export class Service {

  subject = new Subject<string[]>;

  observable$ = this.subject.asObservable();

  constructor(private http: Http) {}

  observable: Observable<string[]>;

  get(link: string): Observable<string[]> {
    this.observable$ = this.http.get('myapi.com')
                    .map((res: Response) => this.subject.next(res.json())
                    .catch(this.handleError);

    return this.observable$;
  }

  /**
    * Handle HTTP error
    */
  private handleError (error: any) {
    // In a real world app, we might use a remote logging infrastructure
    // We'd also dig deeper into the error to get a better message
    let errMsg = (error.message) ? error.message :
      error.status ? `${error.status} - ${error.statusText}` : 'Server error';
    console.error(errMsg); // log to console instead
    return Observable.throw(errMsg);
  }
}

The GetComponent responsible for getting the data GetComponent负责获取数据

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Service } from '../shared/index';


@Component({
  moduleId: module.id,
  selector: 'get',
  templateUrl: 'get.component.html',
  providers: [Service],
})
export class GetComponent {

  constructor(public service: Service) {}

  submit() {
    this.service.get(this.url).subscribe();
  }
}

The DisplayComponent responsible for displaying the data DisplayComponent负责显示数据

import { Component, OnInit, OnDestroy } from '@angular/core';

import { Subscription } from 'rxjs/Subscription';


@Component({
  moduleId: module.id,
  selector: 'display',
  templateUrl: 'display.component.html'
})
export class DisplayComponent {
  subscription: Subscription;

  constructor(public service: Service) {}

  ngOnInit() {
    // the observable is undefined :(
    this.subscription = this.service.observable$.subscribe(data => {
      console.log(data);
    },
    error => {
      // this never gets reached :(
    })
  }
  ngOnDestroy() {
    // prevent memory leak when component is destroyed
    this.subscription.unsubscribe();
  }
}

This design works ok except the error handling does not work for the DisplayComponent . 除错误处理不适用于DisplayComponent之外,此设计可以正常进行。 Also the map function in the HttpService doesn't seem quite right this.subject.next(res.json() 另外HttpService中的map函数看起来不太正确this.subject.next(res.json()

Also it doesn't seem quite right that the GetComponent has to "subscribe" like this this.service.get(this.url).subscribe(); 同样,GetComponent不得不像这样this来“订阅”似乎也不是正确的。service.get this.service.get(this.url).subscribe();

What is the proper way to design this sort of thing? 设计此类事物的正确方法是什么? How can I get the DisplayComponent to observe errors thrown by the HttpComponent 如何获取DisplayComponent来观察HttpComponent引发的错误

Your code has several problems where Service.$observable is modified several times: 您的代码有几个问题,其中Service。$ observable被多次修改了:

observable$ = this.subject.asObservable();
this.observable$ = this.http.get('myapi.com') .... // remove this line

The right way to do this: Get Component calls Service to get data. 正确的方法: Get Component调用Service以获取数据。 After data is loaded, Get Component emits a Data Ready event with the data. 加载数据后,“ Get Component将与数据一起发出“ Data Ready事件。 Display Component , and other components that use this data, listen to DataReady event and update data when the event is emitted. Display Component以及使用此数据的其他组件,侦听DataReady事件并在事件发出时更新数据。

Code to explain my answer: 代码来解释我的答案:

@Injectable()
export class GetService {
  /// subject
  subject = new Subject<string[]>()

  /// the observable
  observable = this.subject.asObservable()


  constructor(private $http: Http) {

  }

  /// get data
  getData() {
    // not override observable here
    this.$http.get("api.com")
      .map(response => response.json()) // map the data
      .subscribe((data: string[]) => this.subject.next(data), // emit data event
              error => this.subject.error(error)) // emit error event
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM