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);
我的目标是将一个可观察对象从父组件传递给它的子组件,我不能使用“输入”和“输出”来实现,因为包含子组件的组件本身就是内部库的组件用于用户界面。
我有一个父亲组件: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);