Angular 4-Service中rxjs BehaviorSubject的用法 [英] Angular 4 - rxjs BehaviorSubject usage in Service

查看:218
本文介绍了Angular 4-Service中rxjs BehaviorSubject的用法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的服务代码如下-

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

搜索组件(在服务之上并且也可以订阅)看起来像下面-

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

如上所述,由于没有打印任何日志并且控制台中也没有出现任何错误,因此控件没有在观察组件的subscription方法中出现在这里.不确定我是否以正确的方式使用BehaviorSubject.

我试图关注以下链接-

角度2-行为主题与可观察性?->不输入订阅如此处所述.
http-observables ->当我尝试这种方式时,它确实输入了subscription,但随后引发了日志错误-

无法读取null的属性xyz 因为甚至在我从服务获取数据之前就已打印组件日志.在遇到上述错误之后,服务日志随后才打印.

我的意图不是从SearchComponent本身订阅会打击服务的BehaviorSubject.我只是想测试我是否从 any 组件的服务中获取值.我认为这与从任何需要 serviceRequestDto 值作为订阅语法在所有组件中均保持不变.

更新1:

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

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

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

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

 }

请注意,我之前在 service 代码-

中使用了以下代码

private serviceRequestDtoSource = new BehaviorSubject<ServiceRequestDto>(null);
serviceRequestDto$ = this.serviceRequestDtoSource.asObservable();

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

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

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

我的初始代码与我现在发布的代码不同,它基于以下链接-解决方案

我认为这取决于一个事实,即BehaviorSubject订阅后始终会发出其第一个值(请参见此处的大理石图

Search Component (which hits above service and also subscribes) looks like below -

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

As mentioned above, control doesn't come here inside observing component's subscribe method as none of the logs are printed and also I don't get any error in console.Not sure if I'm using BehaviorSubject in proper way.

I tried to follow following links -

Angular 2 - Behavior Subject vs Observable? -> Not entering subscribe as mentioned here.
http-observables -> When I tried this way , it does enter subscribe but then throws error for logs -

cannot read property xyz of null as component logs gets printed even before i get data from service.Service logs got printed later after i got above mentioned error.

My intention is not to subscribe to the BehaviorSubject from SearchComponent itself which hits the service. I'm just trying to test if i get the values from service in any component.I believe it's as good as subscribing from any other component which needs serviceRequestDto values as syntax for subscribing remains same from all components.

Update 1:

I tried to use ReplaySubject(1) as suggested by Brandon, but still i was getting below error while subscribing to subject in component.

TypeError: Cannot read property 'name' of undefined(…)

My updated service code looks like this now -

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

 }

Please note earlier I was using following in service code -

private serviceRequestDtoSource = new BehaviorSubject<ServiceRequestDto>(null);
serviceRequestDto$ = this.serviceRequestDtoSource.asObservable();

My updated Search Component code looks like this -

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

The way earlier component code was subscribing to subject was different and control never went inside component's subscribe though there was no error.

My initial code is different from what I've posted now and it was based on following link - delegation-eventemitter-or-observable-in-angular2

解决方案

I think this depends on the fact that BehaviorSubject emits always its first value as soon as it is subscribed (see marble diagram here http://reactivex.io/RxJava/javadoc/rx/subjects/BehaviorSubject.html).

Now the first value emitted in your case is null, i.e. The value you passed in the constructor of BehaviorSubject.

One way to overcome the problem is to use check for not null values (now that you know that there may be a legitimate one) or use the operator skip() to skip always the first emitted value.

这篇关于Angular 4-Service中rxjs BehaviorSubject的用法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆