首页 > 解决方案 > 如何正确地将 HttpClient 请求的结果多播到 Angular 中的多个组件?

问题描述

我正在尝试HttpClient post在我的 Angular 应用程序中发送请求多个组件的结果。每当成功执行新请求时,我都会使用Subject并调用它的方法。每个组件订阅服务的.next()postSubject

故障服务定义为

@Injectable()
export class BuildingDataService {

  public response: Subject<object> = new Subject<object>();

  constructor (private http: HttpClient) { }

  fetchBuildingData(location) {
    ...

    this.http.post(url, location, httpOptions).subscribe(resp => {
      this.response.next(resp);
    });
}

订阅的组件BuildingService.response如下

@Component({
  template: "<h1>{{buildingName}}</h1>"
  ...
})

export class SidepanelComponent implements OnInit {
  buildingName: string;

  constructor(private buildingDataService: BuildingDataService) { }

  ngOnInit() {
    this.buildingDataService.response.subscribe(resp => {
        this.buildingName = resp['buildingName'];
      });
  }

  updateBuildingInfo(location) {
    this.buildingDataService.fetchBuildingData(location);
  }
}

updateBuildingInfo由用户点击地图触发。

从服务器检索数据并将其传递给组件是可行的:我可以将有效负载输出到每个组件的控制台。但是,组件的模板无法更新。

在今天大部分时间谷歌搜索和摆弄之后,我发现这个实现不会触发 Angular 的更改检测。解决方法是

对于这样一个微不足道的用例,这两种解决方案都感觉像是肮脏的黑客攻击。必须有更好的方法来实现这一点。

因此,我的问题是:一次获取数据并将其发送到多个组件的正确方法是什么?

我还想了解为什么我的实现会避开 Angular 的变更检测系统。

编辑原来我是HttpClient在 Angular 区域之外发起呼叫,因此它无法检测到我的更改,有关更多详细信息,请参阅我的答案。

标签: javascriptangulartypescriptngx-leaflet

解决方案


一种方法是使用管道获取并在模板ObservableSubject使用它:async

(building | async)?.buildingName

此外,如果不同的组件在不同的时间订阅服务,您可能必须BehaviorSubject使用Subject.


@Injectable()
export class BuildingDataService {
  private responseSource = new Subject<object>();
  public response = this.responseSource.asObservable()

  constructor (private http: HttpClient) { }

  fetchBuildingData(location) {
    this.http.post(url, location, httpOptions).subscribe(resp => {
      this.responseSource.next(resp);
    });
  }
}

@Component({
  template: "<h1>{{(building | async)?.buildingName}}</h1>"
  ...
})

export class SidepanelComponent implements OnInit {
  building: Observable<any>;

  constructor(private buildingDataService: DataService) {
      this.building = this.buildingDataService.response;
  }

  ngOnInit() {
  }

  updateBuildingInfo(location) {
    this.buildingDataService.fetchBuildingData(location);
  }
}

推荐阅读