Je l'ai fait plusieurs fois dans mon application. C'est simple, ça devrait marcher ... Mais cette fois ça ne marche pas.
Mon problème:
J'appelle une méthode dans un service à partir d'un composant A, mon composant B est abonné mais ne réagit ni ne reçoit rien. subscribe()
ne se déclenche pas!
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
composant
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();
}
}
Ce composant déclenche la méthode du service: updateIBOsNavigation
.
IBOsNavigationElement
composant
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() {
}
}
Ce composant est inscrit, il doit être répertorié et recevoir les données ...
Trions DI: Tenez compte du fait que IboDetailsGeneral
est dans une couche inférieure de la structure de l'application, donc IboDetailsGeneral
est enfant of IBOsNavigationElement
.
C'est pourquoi j'ajoute NavigationElementsService
dans le module de IBOsNavigationElement
:
NavigationModule
est le module de IBOsNavigationElement
@NgModule({
imports: [
// A lot of stuff
],
declarations: [
// A lot of stuff
IBOsNavigationElement
],
exports: [
// A lot of stuff
],
providers: [
NavigationElementsService
]
})
Console:
APPEL à la mise à jourIBOsNavigation FUNCTION
updateIBOsNavigation "95"
MISE À JOUR DE LA FONCTION IBONavigation
updateIBOsNavigation "test"
Les résultats de cette console m'indiquent que:
Mes tests:
IBOsNavigationElement
(l'auditeur), et la communication avec le service est bonne.NavigationElementsService
est ajouté à providers
est dans NavigationModule
, donc il n'y a qu'une seule instance du service, n'est-ce pas? Ensuite, le problème expliqué dans le lien suivant n'a pas lieu: L'abonnement observable Angular 2 ne se déclenche pasJe suis vraiment désolé pour mon 'mur de texte' mais à ce stade, je suis un peu désespéré.
Toute aide est appréciée, merci!
Mise à jour 1:
Après la première réponse, j'ai essayé plusieurs choses ...
Utilisation de ReplaySubject
:
@Injectable()
export class NavigationElementsService {
public updateIBOsNavigation$ = new ReplaySubject();
updateIBOsNavigation(navigationData) {
log.d('updateIBOsNavigation', JSON.stringify(navigationData));
this.updateIBOsNavigation$.next(navigationData);
}
}
Résultat: lors de l'appel de updateIBOsNavigation()
, subscribe()
ne se déclenche toujours pas.
Utilisation de 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);
}
}
Résultat: Il entre subscribe()
à l'initialisation mais quand j'appelle updateIBOsNavigation()
, subscribe()
ne se déclenche toujours pas.
Utilisation de BehaviorSubject
v2:
J'ai essayé cette approche: behaviorSubject dans angular2, comment cela fonctionne et comment l'utiliser
@Injectable()
export class NavigationElementsService {
public updateIBOsNavigation$: Subject<string> = new BehaviorSubject<string>(null);
updateIBOsNavigation(navigationData) {
log.d('updateIBOsNavigation', JSON.stringify(navigationData));
this.updateIBOsNavigation$.next(navigationData);
}
}
Résultat: identique à l'application précédente de BehaviorSubject
.
Mise à jour 2:
Plus d'échantillons de tentatives désespérées après des recherches sur le Web ...
Utilisation de 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);
}
}
Résultat: Identique aux précédentes tentatives de BehaviorSubject
... Le désespoir augmente ...
Mise à jour 3:
Au cas où, je voulais m'assurer que NavigationElementsService
est un singleton:
export class NavigationModule {
static forRoot() {
return {
ngModule: NavigationModule,
providers: [NavigationElementsService]
};
}
}
Et lors de l'importation:
imports: [
NavigationModule.forRoot()
]
Résultat: Même problème que d'habitude, subscribe()
ne se déclenchant pas, mais au moins je sais qu'il existe une instance de NavigationElementsService
.
Je pense que le problème est votre type Subject
Avec Subject
, aucun composant qui s'abonne après le déclenchement d'un événement ne recevra de valeur. Pour relire la valeur précédente aux abonnés en retard, utilisez BehaviorSubject
ou ReplaySubject
au lieu de Subject
.
En savoir plus sur les différents types de sujets de http://reactivex.io/documentation/subject.html
Sujet du comportement
Lorsqu'un observateur s'abonne à un BehaviorSubject, il commence par émettre l'élément le plus récemment émis par l'observable source (ou une valeur de départ/valeur par défaut si aucun n'a encore été émis), puis continue d'émettre tout autre élément émis ultérieurement par l'observable source ( s).
ReplaySubject
ReplaySubject émet à tout observateur tous les éléments qui ont été émis par le ou les observables source, quel que soit le moment où l'observateur s'abonne.
Un BehaviorSubject
nécessite une valeur par défaut lors de sa configuration. Vous devez donc le créer avec une sorte de valeur:
updateIBOsNavigationSubject = new BehaviorSubject<any>('');
updateIBOsNavigation$ = this.updateIBOsNavigationSubject.asObservable();
updateIBOsNavigation(navigationData) {
log.d('updateIBOsNavigation', JSON.stringify(navigationData));
this.updateIBOsNavigationSubject.next(navigationData);
}
Un ReplaySubject
ne nécessite pas de valeur par défaut.
[~ # ~] modifier [~ # ~]
Lors de l'utilisation d'un service partagé, il est également important de s'assurer que le service est fourni UNIQUEMENT au niveau du module racine. Si plusieurs emplacements sont fournis, les composants peuvent ne pas obtenir la même instance. Même si le service est fourni au niveau racine, si un module entre le niveau racine et votre composant fournit le service, une nouvelle instance sera envoyée dans cette branche de l'arborescence Injection de dépendances.
J'espère que cela t'aides.
Lorsque nous incluons un service dans les "fournisseurs", il est instancié et cet état est maintenu entre ses composants ainsi que ses composants enfants.
Et, si nous incluons le service dans le tableau de fournisseur des deux composants, il ne suit plus singleton. L'Etat sera indépendant et non partagé entre eux.
Donc, n'incluez votre service qu'au composant parent ou à votre composant racine.
J'ai moi aussi fait face à ce problème et résolu avec l'aide de cette solution ici, https://stackoverflow.com/a/38034298/5730167 .