Angular 4 - 服务中的rxjs BehaviorSubject用法

cod*_*r87 2 rxjs behaviorsubject angular

我的服务代码如下所示 -

DataService的

@Injectable()
export class DataService {
...
private serviceRequestDtoSource = new BehaviorSubject<ServiceRequestDto>(null);
serviceRequestDto$ = this.serviceRequestDtoSource.asObservable();
...
getAccountInfo(serviceRequestDto : ServiceRequestDto){
    let body = JSON.stringify(serviceRequestDto);
    let headers = new Headers({
        'Content-Type': 'application/json'
    });
    let options = new RequestOptions({ headers: headers });
    console.log("In data service.getAccountInfo");
    this.http
        .post(this.clientAccountInfoURL, body, options)
        .map((response : Response) => { return <AccountDto[]> response.json().accountDtoList})
        .do(data=> console.log('All :'+ JSON.stringify(data)))
        .subscribe( response => { 
                             this.accountList = response; 
                             this.serviceRequestDto.accountDtoList = this.accountList;
                             this.serviceRequestDtoSource.next(serviceRequestDto);
                         },
                         error => this.errorMessage = <any>error);
}
Run Code Online (Sandbox Code Playgroud)

搜索组件(点击服务并订阅)如下所示 -

onSearch(value) {  
...
this.dataService.getAccountInfo(this.serviceRequestDto); //service call
this.subscription = this.dataService.serviceRequestDto$
        .subscribe( (serviceRequestDtoValue : ServiceRequestDto) => {
        // Control doesn't come here..
         this.serviceRequestDto = serviceRequestDtoValue;
         console.log('search.serviceRequestDto.length:'+this.serviceRequestDto.accountDtoList.length);
         console.log('search.serviceRequestDto.accountDtoList.name:'+this.serviceRequestDto.accountDtoList[0].name);
    });
Run Code Online (Sandbox Code Playgroud)

如上所述,控制不会出现在观察组件的订阅方法中,因为没有打印任何日志,并且我也没有在控制台中收到任何错误.不确定我是否正确使用BehaviorSubject.

我试着按照以下链接 -

角度2 - 行为主体与可观察对象? - >不按此处所述输入订阅.
http-observables - >当我尝试这种方式时,它确实输入了subscribe但是然后抛出了日志错误 -

因为组件日志甚至在我从service获取数据之前就读取了属性xyz of null.在上面提到的错误之后,服务日志被打印出来了.

我的目的不是订阅SearchComponent本身的BehaviorSubject,它会点击服务.我只是想测试我是否从任何组件中的服务获取值.我相信它与从任何其他需要serviceRequestDto值的组件订阅一样好,因为订阅的语法从所有组件保持相同.

更新1:

我尝试使用Brandon建议的ReplaySubject(1),但在订阅组件中的主题时仍然遇到错误.

TypeError:无法读取未定义的属性"name"(...)

我的更新服务代码现在看起来像这样 -

serviceRequestDtoSource = new ReplaySubject<ServiceRequestDto>(1);
getAccountInfo(serviceRequestDto : ServiceRequestDto){
 ...
 //Logic same as earlier
 //I'm getting all values from service here in the logs I print

 }
Run Code Online (Sandbox Code Playgroud)

请注意,之前我在服务代码中使用了以下内容-

private serviceRequestDtoSource = new BehaviorSubject<ServiceRequestDto>(null);
serviceRequestDto$ = this.serviceRequestDtoSource.asObservable();
Run Code Online (Sandbox Code Playgroud)

我更新的搜索组件代码如下所示 -

this.dataService.getAccountInfo(this.serviceRequestDto);
this.dataService.serviceRequestDtoSource.subscribe((serviceRequestDtoValue : ServiceRequestDto) => {
this.serviceRequestDto = serviceRequestDtoValue;
console.log('search.serviceRequestDto.length:'+this.serviceRequestDto.accountDtoList.length);           
// prints 'search.serviceRequestDto.length:0'
console.log('search.serviceRequestDto.accountDtoList   name:'+this.serviceRequestDto.accountDtoList[0].name); // throws 'vendor.bundle.js:5764 ERROR TypeError: Cannot read property 'name' of undefined(…)' error
});
Run Code Online (Sandbox Code Playgroud)

早期组件代码订阅主题的方式是不同的,虽然没有错误,但控件从未进入组件的订阅.

我的初始代码与我现在发布的代码不同,它基于以下链接 - delegation-eventemitter-or-observable-in-angular2

Pic*_*cci 6

我认为这取决于BehaviorSubject一旦订阅就会发出它的第一个值(参见大理石图http://reactivex.io/RxJava/javadoc/rx/subjects/BehaviorSubject.html).

现在,在您的情况下发出的第一个值为null,即您在BehaviorSubject的构造函数中传递的值.

解决此问题的一种方法是使用检查非空值(现在您知道可能存在合法值)或使用运算符skip()始终跳过第一个发射值.

  • 使用`ReplaySubject(1)`而不是`BehaviorSubject(null)`来避免获得第一个空值. (6认同)