2016-10-10 13 views
2

モーダルウィンドウ内にあるいくつかのコンポーネント間の通信に共有サービスを使用していますが、モーダルウィンドウ内のモーダル内に設定されている値を取得しようとしています。それが存在するコンポーネントです。角2 RxJS Observable Skipping最初の呼び出しを購読する

私のサービスでgetSelectedSourceField関数を購読すると、ユーザーがモーダルでソースを最初に選択したときに購読をスキップしますが、それ以降は期待どおりに機能します(つまり、選択したフィールドを成功折り返し電話)。

どのような考えですか?

マイサービス:

import { Component, ViewChild, OnInit } from '@angular/core'; 
import { DataService } from '../../services/dataService'; 
import { Response, Headers } from '@angular/http'; 
import { Condition } from '../transformation'; 
import { NgbModal, ModalDismissReasons } from '@ng-bootstrap/ng-bootstrap'; 
import { SourceFieldListComponent } from '../../source/selection/sourcefield-list.component'; 
import { SourceListComponent } from '../../source/selection/source-list.component'; 
import { SFieldSelectService } from '../../services/source-select.service'; 

@Component({ 
    selector: 'condition-addedit', 
    templateUrl: 'app/transformation/condition/condition-addedit.component.html', 
    providers: [DataService, SFieldSelectService] 
}) 
export class ConditionAddEditComponent implements OnInit { 
    active: boolean = true; 
    condSeqCount = 1; 
    selectingCondition: Condition; 
    hasSelectedSourceField: boolean = false; 

    //List of Conditions currently in the add/edit list 
    public conditions: Condition[] = []; 

    //Modal Functions 
    closeResult: string; 
    openSourceSelect(content, condition) { 
     this.selectingCondition = condition; 
     this.modalService.open(content, { size: 'lg' }).result.then((result) => { 
      //User selected source field in modal 
      if (result == 'Select SField') { 
       this.selectService.getSelectedSourceField() 
        .subscribe(sourceField => { <--- SKIPS THIS THE FIRST TIME BUT NOT AFTER 
         alert(sourceField.name); 
         this.selectingCondition.sourceField = sourceField 
        } 
       , (error) => alert(error)); 
      } 
     }, (reason) => { 
      this.closeResult = `Dismissed ${this.getDismissReason(reason)}`; 
     }); 
    } 

    private getDismissReason(reason: any): string { 
     if (reason === ModalDismissReasons.ESC) { 
      return 'by pressing ESC'; 
     } else if (reason === ModalDismissReasons.BACKDROP_CLICK) { 
      return 'by clicking on a backdrop'; 
     } else { 
      return `with: ${reason}`; 
     } 
    } 

    //Add a new condition to the list of conditions 
    addCondition() { 
     this.conditions.push(new Condition(this.condSeqCount++, (this.condSeqCount == 1) ? '' : 'or', '', '', '', '', null)); 
    } 

    constructor(private _dataService: DataService, private modalService: NgbModal, private selectService: SFieldSelectService) {} 
    ngOnInit(): void { 
     this.selectService.hasSelectedSourceField().subscribe(hasSelectedSourceField => this.hasSelectedSourceField = hasSelectedSourceField); 
    } 
} 
+0

これは、ngOnInitを購読して変数に代入し、その変数に "selectingCondition"を設定するだけで回避できました。しかし、私の質問の例では何が起きているのか不思議です。 – Deej

答えて

2

はたぶんngOnInitはより良いアプローチ、確かではありません。私は加入してい

import { Injectable } from '@angular/core'; 
import { Subject } from 'rxjs/Subject'; 
import { Observable } from 'rxjs/Observable'; 
import { Source, SourceField } from '../source/source'; 
import { DataService } from './dataService'; 

@Injectable() 
export class SFieldSelectService { 
private selectedSource: Source = null; 
private selectedSourceField: SourceField = null; 
private filteredSourceFields: SourceField[] = []; 

private selectedSourceSubj = new Subject<Source>(); 
private selectedSourceFieldSubj = new Subject<SourceField>(); 
private filteredSourceFieldsSubj = new Subject<SourceField[]>(); 
private hasSourceFieldSubj = new Subject<boolean>(); 

//Source methods 
setSelectedSource(source: Source) { 
    this.selectedSource = source; 
    this.selectedSourceSubj.next(source); 

    //Set the availabel source fields 
    this._dataService.GetSingle('SourceSelect', this.selectedSource["sourceId"]) 
     .subscribe(sourceFields => { 
      this.filteredSourceFields = sourceFields 
      this.filteredSourceFieldsSubj.next(sourceFields); 
     }); 

    this.hasSourceFieldSubj.next(false); 
} 
getSelectedSource(): Observable<Source> { 
    return this.selectedSourceSubj.asObservable(); 
} 

//Sourcefield methods 
setSelectedSourceField(sourceField: SourceField) { 
    this.selectedSourceField = sourceField; 
    this.selectedSourceFieldSubj.next(sourceField); 

    this.hasSourceFieldSubj.next(true); 
} 
getSelectedSourceField(): Observable<SourceField> { 
    return this.selectedSourceFieldSubj.asObservable(); 
} 

//Filtered sourcefields 
getFilteredSourceFields(): Observable<SourceField[]> { 
    return this.filteredSourceFieldsSubj.asObservable(); 
} 

//Whether or not the modal has a selected sourcefield 
hasSelectedSourceField(): Observable<boolean> { 
    return this.hasSourceFieldSubj.asObservable(); 
} 

constructor(private _dataService: DataService) {} 
} 

コンポーネント。しかし、問題の理由は、Subjectの使用です。いったんあなたが何かを放射すれば、放射の時に加入した人がいなければ、その放射は永遠に失われます。

これは、ReplaySubjectが役に立つ場合があります。それはあなたがバッファサイズを設定することを可能にし、誰かが購読しているときにバッファに何かがあるならば、そのバッファからの全ての排出量です。多くの場合、最後にバッファリングされたもの(最新のもの)だけをバッファに入れたいので、バッファサイズを1にします。

import { ReplaySubject } from 'rxjs/ReplaySubject'; 

class Service { 
    something = new ReplaySubject<Source>(1); // buffer size 1 
} 

このようにすると、最新の放射のサービスのフィールドを維持しようとする必要はありません。それは既に被験者自身に保存されています。

+0

ReplaySubjectが動作するようです。私は先に進んでngOnInitに固執すると思いますが、これはちょっとしたことがベストプラクティスと思われるので、私はそのプロパティのReplaySubjectに切り替えます。ありがとう! – Deej

1

@peeskilletが示唆しているように、ここではSubjectの使用が問題になる可能性があります。あなたが記述したユースケースについては、私は通常BehaviorSubjectを使用します。より良いオプションがない場合はnullで初期化することができます。

実際には、コンポーネント/サービス間で値を共有している場合、ほとんどの場合、Subject(または他の* Subject)に対してBehaviorSubjectを使用したいと考えています。それはちょうどあなたに '現在/最新'の値を与えます。その点についてはpost on angular-universityです。

関連する問題