web-dev-qa-db-ja.com

Angular 2:観察可能/サブスクリプションがトリガーされない

私はアプリでこれを複数回行いました。簡単で、動作するはずです...しかし、今回は動作しません。

私の問題:

コンポーネントAからサービスのメソッドを呼び出しています。コンポーネントBはサブスクライブされていますが、反応も受信もしません。 subscribe()はトリガーしていません!

navigation-elements.service.ts

_@Injectable()
export class NavigationElementsService {
    updateIBOsNavigation$: Observable<any>;

    private updateIBOsNavigationSubject = new Subject<any>();

    constructor() {
        this.updateIBOsNavigation$ = this.updateIBOsNavigationSubject.asObservable();
    }

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation', JSON.stringify(navigationData));
        this.updateIBOsNavigationSubject.next(navigationData);
    }
}
_

IboDetailsGeneral component

_export class IboDetailsGeneral implements OnInit, OnDestroy {
    id: string;
    private sub: any;

    constructor(private route: ActivatedRoute, private iboService: IBOsService, private navigationService: NavigationElementsService) {
        this.sub = this.route.params.subscribe(params => {
            this.id = params['id'];

            console.log('CALLING updateIBOsNavigation FUNCTION');
            this.navigationService.updateIBOsNavigation(this.id);
        });
    }

    ngOnInit() {
        console.log('CALLING updateIBOsNavigation FUNCTION AGAIN');
        this.navigationService.updateIBOsNavigation('test');
    }

    ngOnDestroy() {
        this.sub.unsubscribe();
    }
}
_

このコンポーネントは、サービスのメソッドupdateIBOsNavigationをトリガーします。

IBOsNavigationElement component

_export class IBOsNavigationElement implements OnInit {
    private id: string;

    constructor(private navigationService: NavigationElementsService) {
        this.navigationService.updateIBOsNavigation$.subscribe((navigationData) => {
                log.d('I received this Navigation Data:', JSON.stringify(navigationData));
                this.id = navigationData;
            }
        );
    }

    ngOnInit() {
    }
}
_

このコンポーネントはサブスクライブされてお​​り、データをリストして受信する必要があります...

DIを整理しましょう:IboDetailsGeneralはアプリの構造の下位層にあるため、IboDetailsGeneralchildIBOsNavigationElement

NavigationElementsServiceのモジュールにIBOsNavigationElementを追加する理由は次のとおりです。

NavigationModuleIBOsNavigationElementのモジュールです

_@NgModule({
    imports: [
        // A lot of stuff
    ],
    declarations: [
        // A lot of stuff
        IBOsNavigationElement
    ],
    exports: [
        // A lot of stuff
    ],
    providers: [
        NavigationElementsService
    ]
})
_

コンソール:

CALLING updateIBOsNavigation FUNCTION

updateIBOsNavigation "95"

CALLING updateIBOsNavigation Function AGAIN

updateIBOsNavigation「テスト」

このコンソールの結果から次のことがわかります。

  • メソッドが呼び出されているため、プロバイダーエラーはありません。 サービスとの通信はOKです

私のテスト:

  • IBOsNavigationElement(リスナー)でランダムメソッドを呼び出してみましたが、サービスとの通信は良好です。
  • NavigationElementsServiceprovidersが追加される唯一の場所はNavigationModuleにあるため、サービスのインスタンスは1つだけです。その後、次のリンクで説明されている問題は発生しません: Angular 2 observable subscription not triggering

私は 'テキストの壁'に本当に申し訳ありませんが、この時点で私はちょっと必死です。

どんな助けも感謝します、ありがとう!

更新1:

最初の答えの後、私はいくつかのことを試しました...

ReplaySubjectの使用

_@Injectable()
export class NavigationElementsService {
    public updateIBOsNavigation$ = new ReplaySubject();

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation', JSON.stringify(navigationData));
        this.updateIBOsNavigation$.next(navigationData);
    }
}
_

結果:updateIBOsNavigation()を呼び出すとき、subscribe()はまだトリガーしていません。

BehaviorSubjectの使用

_@Injectable()
export class NavigationElementsService {
    updateIBOsNavigationSubject = new BehaviorSubject<any>('');
     updateIBOsNavigation$ = this.updateIBOsNavigationSubject.asObservable();

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation', JSON.stringify(navigationData));
        this.updateIBOsNavigationSubject.next(navigationData);
    }
}
_

結果:初期化時にsubscribe()に入りますが、updateIBOsNavigation()を呼び出すと、subscribe()はまだトリガーされません。

BehaviorSubject v2を使用:

私はこのアプローチを試しました: behaviourSubject in angle2、それがどのように機能し、どのように使用するか

_@Injectable()
export class NavigationElementsService {
    public updateIBOsNavigation$: Subject<string> = new BehaviorSubject<string>(null);

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation', JSON.stringify(navigationData));
        this.updateIBOsNavigation$.next(navigationData);
    }
}
_

結果:以前のBehaviorSubjectの適用と同じ。

更新2:

ウェブ全体を調査した後の必死の試みのサンプル.

BehaviorSubject v3を使用:

_@Injectable()
export class NavigationElementsService {
    updateIBOsNavigation$: Observable<any>;
    updateIBOsNavigationSubject = <BehaviorSubject<any>> new BehaviorSubject([]);

    constructor() {
        this.updateIBOsNavigation$ = this.updateIBOsNavigationSubject.asObservable();
    }

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation()', JSON.stringify(navigationData));
        this.updateIBOsNavigationSubject.next(navigationData);
    }
}
_

結果:前のBehaviorSubject試行と同じ...絶望が高まっています...

更新3:

念のため、NavigationElementsServicesingletonであることを確認したかった:

_export class NavigationModule {
    static forRoot() {
        return {
            ngModule: NavigationModule,
            providers: [NavigationElementsService]
        };
    }
}
_

そしてインポートするとき:

_imports: [
        NavigationModule.forRoot()
       ]
_

結果:いつもと同じ問題、subscribe()はトリガーしませんが、少なくともNavigationElementsServiceのインスタンスが1つあることは知っています。

16
SrAxi

問題はあなたのSubjectタイプだと思いますSubjectでは、イベントが発生した後にサブスクライブするコンポーネントは値を受け取りません。前の値を遅いサブスクライバにリプレイするには、BehaviorSubjectの代わりにReplaySubjectまたはSubjectを使用します。

http://reactivex.io/documentation/subject.html のさまざまなサブジェクトタイプの詳細

行動主題

オブザーバーがBehaviorSubjectにサブスクライブすると、ソースObservableによって最後に放出されたアイテム(またはまだ放出されていない場合はシード/デフォルト値)の放出から始まり、ソースObservableによって後で放出された他のアイテムの放出を続けます( s)。

ReplaySubject

ReplaySubjectは、オブザーバーがサブスクライブする時期に関係なく、ソースObservableによって発行されたすべてのアイテムを任意のオブザーバーに発行します。

BehaviorSubjectは、セットアップ時にデフォルト値を必要とします。そのため、何らかの値で作成する必要があります。

updateIBOsNavigationSubject = new BehaviorSubject<any>('');
updateIBOsNavigation$ = this.updateIBOsNavigationSubject.asObservable();

updateIBOsNavigation(navigationData) {
    log.d('updateIBOsNavigation', JSON.stringify(navigationData));
    this.updateIBOsNavigationSubject.next(navigationData);
}

ReplaySubjectはデフォルト値を必要としません。

[〜#〜] edit [〜#〜]

共有サービスを使用する場合、ルートモジュールでのみサービスが提供されるようにすることも重要です。複数の場所で提供される場合、コンポーネントは同じインスタンスを取得していない可能性があります。サービスがルートレベルで提供される場合でも、ルートレベルとコンポーネントの間のモジュールがサービスを提供する場合、新しいインスタンスが依存性注入ツリーのそのブランチに送信されます。

お役に立てれば。

35
Tyler Jennings

「プロバイダー」にサービスを含めると、インスタンス化され、コンポーネントと子コンポーネントの間でこの状態が維持されます。

そして、両方のコンポーネントプロバイダー配列にサービスを含めると、シングルトンに続くことはなくなります。状態は独立しており、それらの間で共有されません。

そのため、親コンポーネントまたはルートコンポーネントのみにサービスを含めてください。

私もこの問題に直面し、このソリューションの助けを借りて解決しました https://stackoverflow.com/a/38034298/5730167

5
lalith kumar