组件BehaviorSubject订阅者未收到异步HTTP请求发出的值

时间:2018-10-03 01:02:02

标签: angular

我试图理解为什么这个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请求的异步值,以及如何对其进行修复以使其能够正常工作。

2 个答案:

答案 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);
       }
})