3

私のサービスコードは以下のようになります -

データサービス

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

上記のように、ログが出力されず、コンソールにエラーが表示されないため、監視コンポーネントのサブスクライブ メソッド内に制御が入りません。適切な方法で BehaviorSubject を使用しているかどうかはわかりません。

次のリンクをたどってみました -

Angular 2 - 行動主体と観察対象? →こちらに記載のサブスクライブには入っていません。
http-observables -> この方法を試してみると、サブスクライブに入りますが、ログのエラーがスローされます -

サービスからデータを取得する前でもコンポーネント ログが印刷されるため、null のプロパティ xyz を読み取れません 。上記のエラーが発生した後、サービス ログが後で印刷されます。

私の意図は、サービスにヒットする SearchComponent 自体から BehaviorSubject にサブスクライブすることではありません。コンポーネントのサービスから値を取得するかどうかをテストしようとしています。サブスクライブの構文はすべてのコンポーネントで同じであるため、 serviceRequestDto値を必要とする他のコンポーネントからサブスクライブするのと同じくらい良いと思います。

更新 1:

ブランドンの提案に従って ReplaySubject(1) を使用しようとしましたが、コンポーネントでサブジェクトをサブスクライブしているときにエラーが発生しました。

TypeError: undefined(…) のプロパティ '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

 }

以前、サービスコードで次を使用していたことに注意してください-

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

以前のコンポーネント コードがサブジェクトにサブスクライブしていた方法は異なり、エラーはありませんでしたが、コントロールがコンポーネントのサブスクライブ内に入ることはありませんでした。

私の最初のコードは、現在投稿したものとは異なり、次のリンクに基づいていました- delegation-eventemitter-or-observable-in-angular2

4

2 に答える 2

6

これは、サブスクライブされるとすぐに BehaviorSubject が常に最初の値を発行するという事実に依存していると思います (こちらの大理石の図を参照してくださいhttp://reactivex.io/RxJava/javadoc/rx/subjects/BehaviorSubject.html )。

あなたのケースで発行された最初の値は null です。つまり、BehaviorSubject のコンストラクターに渡した値です。

この問題を解決する 1 つの方法は、null 以外の値のチェックを使用するか (正当な値が存在する可能性があることがわかっているため)、演算子 skip() を使用して最初に発行された値を常にスキップすることです。

于 2017-06-15T18:12:46.327 に答える