Angular 11 - 如何使用服务传递可观察到的数据

Angular 11 - How to pass data observable using a service

我的目标是将一个可观察对象从父组件传递给它的子组件,我不能使用“输入”和“输出”来实现,因为包含子组件的组件本身就是内部库的组件用于用户界面。

我有一个父亲组件:home.componente.ts

在父组件 HomeComponent 中,我从 OnInit 事件调用服务并将其响应存储在“Subject”类型中以存储可观察对象,以便我可以订阅子组件:

this.tabs = [            
   {id: 'reportsTab', label: 'Files', routerLink: '/reports/1'},
   {id: 'processesTab', label: 'Tasks', routerLink: '/processes/1'},
];
ngOnInit(): void {
    this.processesService.getInfo(id).subscribe(response => { 
        this.processesService.data.next(response);
    });
}

这是 processes.service.ts 服务:

export class ProcessesService {
    data: Subject<RestResponse<ScheduleDataOutput[]>> = new Subject();
    
    public getInfo(id: number): Observable<RestResponse<ScheduleDataOutput[]>> {
      let serviceName = "/processes/info";
      if (id) {
        serviceName = serviceName + '?id=' + id;
      }
      return this.service.get<any>(serviceName)
      .pipe(
        tap(_ => this.log('fetched info')),
        catchError(this.handleError<ScheduleDataOutput[]>('getInfo', []))
      );
    }
    
    getData() {
        return this.data.asObservable()
    }
}

在home.component.html文件中,我们有内部组件,它是一个UI组件,用于使用标签的经典系统,每个标签都是一个子组件:

<app-menu-tab [tabs]="tabs"></app-menu-tab>

当我点击一个选项卡时,它有一个加载子组件的 routerLink,我想将在 HomeComponent 中获得的响应(可观察的)传递给它,订阅子组件中的可观察对象并使用该响应在子组件中绘制数据网格。

如果我使用在 HomeComponent 组件中获得的响应正确加载子组件的数据网格,则在刷新屏幕时,问题是当我单击选项卡时,数据网格未加载。

这是“reportsTab”选项卡组件的 OnInit 事件:

ngOnInit(): void {
    // Here I access
    this.reportsSubscription = this.processesService.getData().subscribe(response => {
        // But within the subscription I do not access.
        console.log("response: ", response)
    });
}

问题是我无法在订阅内访问,有时 observable 配置错误,“processesTab”选项卡的子组件也会发生同样的情况,当我单击该选项卡时,我无法访问订阅可观察的:

ngOnInit(): void {
    // Here I access
    this.tasksSubscription = this.processesService.getData().subscribe(response => {
        // But within the subscription I do not access.
        console.log("response: ", response)
    });
}

可能是什么问题?如果我将 observable 传递给子组件,但它只能工作并加载数据网格,当我重新加载页面时,但如果我单击选项卡,我将丢失在 HomeComponent 中获得的响应并且数据网格显示为空。

您需要使用 BehaviorSubject(如果不需要初始值,则使用 ReplaySubject),而不是普通的 Subject

BehaviorSubject 将向新订阅者发送最新值,而 Subject 不会这样做。

为了让订阅者获得从主题发出的数据,需要在发出数据之前订阅它。

简而言之,数据属性应该是这样的:

data = new BehaviorSubject<RestResponse<ScheduleDataOutput[]>>(null);

或者,如果初始值是多余的,您可以使用 ReplaySubject 代替:

data = new ReplaySubject<RestResponse<ScheduleDataOutput[]>>(1);