我试图理解为什么这个BehaviorSubject订阅者没有收到发出的值。
在我的组件ngOnInit中,我设置了服务方法的订阅者,该服务方法返回对BehaviorSubject的引用:
// project-detail.component.ts
ngOnInit() {
this.activatedRoute.params.subscribe((data: Params) => {
if (data && data.id) {
this.projectService.getProject(data.id).subscribe(project => {
console.log(project);
});
}
});
}
在服务中,我发出一个http请求,然后将响应数据推送到BehaviorSubject的下一个方法中:
// project.service.ts
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class ProjectService {
private apiUrl = envLocal.apiJsonServerUrl;
private currentProjectObs$ = new BehaviorSubject<IProject>(null);
constructor(private http: HttpClient) {
}
getProject(id: number = 0) {
if (id) {
this.http.get(`${this.apiUrl}/projects/${id}`)
.subscribe(project => {
this.currentProjectObs$.next(project);
});
}
return this.currentProjectObs$;
}
我的理解是,组件ngOnInit中的订阅者应侦听getProject返回的BehaviorSubject参考(即currentProjectObs $)的更改。
当ngOnInit第一次运行时,它将调用getProject,并且由于getProject中的http调用是异步的,因此返回的currentProjectObs $的初始值为null。但是,一旦http get请求完成,就会调用currentProjectObs $ .next(project),并且我希望ngOnInit中的订户会收到新发出的值-但这不会发生。
我想了解这里发生了什么,为什么订阅者没有收到来自http请求的异步值,以及如何对其进行修复以使其能够正常工作。
答案 0 :(得分:0)
我认为您的代码可以简化一点:
// project-detail.component.ts
ngOnInit() {
this.activatedRoute.params.pipe(switchMap(params => {
if (data && data.id) {
return this.projectService.getProject(data.id)
}
// return observable of undefined in case id was not found
return of(undefined);
})).subscribe(actualData => {
console.log("actual data returned by api: ", actualData)
});
}
为您服务:
// project.service.ts
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class ProjectService {
private apiUrl = envLocal.apiJsonServerUrl;
constructor(private http: HttpClient) {
}
getProject(id: number = 0) {
return this.http.get(`${this.apiUrl}/projects/${id}`);
}
您仅应在实际需要数据做某事时在最后订阅。使用Rxjs运算符,数据可以在一个可观察的对象之间流动。 Switch map订阅第一个可观察的对象,并返回另一个我们最后订阅的对象。
让我知道这是否对您有用。
答案 1 :(得分:0)
当您使用下面的函数时,它将再次返回null值,因为它不会等待api调用。并且如果您使用的是Behavior subject
,那么您可以直接从行为主体获取价值,则无需返回它。
getProject(id: number = 0) {
if (id) {
this.http.get(`${this.apiUrl}/projects/${id}`)
.subscribe(project => {
this.currentProjectObs$.next(project);
});
}
return this.currentProjectObs$;
}
您可以使用这两种类型进行操作。确实将其更改为以下内容:
1。不使用行为主题。
// Your Service
getProject(id: number = 0): Observable<any> {
if (id) {
return this.http.get(`${this.apiUrl}/projects/${id}`)
.pipe(map(project => {
return project;
// this.currentProjectObs$.next(project);
});
}
return Observable.of(null);
};
// Your Component
ngOnInit() {
this.activatedRoute.params.subscribe((data: Params) => {
if (data && data.id) {
this.projectService.getProject(data.id)
.subscribe(project => {
console.log(project);
});
}
});
}
2。与行为主题一起使用
// Your service
public currentProjectObs$ = new BehaviorSubject<IProject>(null);
getProject(id: number = 0) {
if (id) {
this.http.get(`${this.apiUrl}/projects/${id}`)
.pipe(map(project => {
this.currentProjectObs$.next(project);
});
}
// return this.currentProjectObs$;
}
// Your component
this.activatedRoute.params.subscribe((data: Params) => {
if (data && data.id) {
this.projectService.getProject(data.id);
}
});
this.projectService.currentProjectObs$
.subscribe(project => {
if(project){
console.log(project);
}
})