7
votes

Abonnement au service de partage de données Angular 6 non déclenché

Je dois définir la valeur dans un composant (composant A) et recevoir la valeur dans un autre composant (composant B). Le composant A et le composant B ne sont pas parent et enfant.

J'ai créé un service partagé pour partager des données entre les 2 composants. Je suis en mesure de définir la valeur du composant B, mais lorsque je m'abonne pour obtenir la valeur du composant A, il n'est pas déclenché.

Voici ce que j'ai essayé:

J'ai ajouté le service dans le tableau @NgModule fournisseurs dans appmodule.ts afin qu'il soit disponible pour tous les composants du projet.

Code de service:

@Component({
  selector: 'app-componenta',
  templateUrl: './componenta.component.html',
  styleUrls: ['./componenta.component.scss']
})


constructor(private socialService: SocialService, private http: HttpClient) {

       this.socialService.getValue().subscribe(data=>{

    console.log('Trigger from ComponentB');
    console.log(data);

});

}

Composant B: Définition de la valeur ici

XXX

Composant A: Obtenez la valeur ici

@Component({
  selector: 'app-componentb',
  templateUrl: './componentb.component.html',
  styleUrls: ['./componentb.component.scss']
})


constructor(private socialService: SocialService, private http: HttpClient) {



}

 buttonClick()
 {

    this.socialService.setValue("linked successfully");
 }

Le déclencheur dans ComponentA est appelé lorsque ComponentA est chargé avec des données étant nul . Mais il n'est pas appelé lorsque buttonClick est appelé depuis ComponentB. p>

J'ai compris le problème, j'aurais dû formuler ma question correctement. Lorsque ComponentA et ComponentB sont dans la même page (URL), le code fonctionne parfaitement.

Comment envoyer des données entre 2 composants lorsqu'ils sont dans 2 pages différentes (URLS).

Exemple: l'utilisateur ouvre l'URL1 (Renders ComponentA) qui a un bouton, l'utilisateur clique sur le bouton et est redirigé vers l'URL2 (Renders ComponentB) dans un nouvel onglet qui a un bouton, lorsque l'utilisateur clique sur le bouton , Je dois transmettre certaines données à ComponentA et fermer URL2. J'ai besoin de récupérer les données passées dans ComponentB et de les utiliser dans URL1. Est-il possible d'utiliser les services? Sinon, quelle approche dois-je suivre?


8 commentaires

Veuillez fournir un exemple reproductible minimal , car cela devrait fonctionner.


Vous pouvez le faire sur stackblitz.com


@trichetriche, j'ai mis à jour ma question, pouvez-vous vérifier.


@TusharWalzade pourriez-vous me guider vers un exemple de code ou un tutoriel?


@RafaelLima s'il vous plaît voir la mise à jour dans ma question.


peut-être que cela pourrait aider angular.io/guide/component-interaction


Avez-vous essayé le ReplaySubject?


cela a fonctionné pour moi aussi dans ionic4


6 Réponses :


0
votes

Dans votre cas, vous devez vous abonner à this.valueObs pour ne pas inclure cette méthode, car votre variable valueObs est de type observable, vous pouvez donc vous abonner directement à cela comme ceci -

constructor(private socialService: SocialService, private http: HttpClient) {

  this.socialService.getValue().subscribe(data=>{
    console.log('Trigger from ComponentB');
    console.log(data);
  });
  this.socialService.valueObs.subscribe(data=>{
    console.log('Trigger from ComponentB on Next called');
  });

}


1 commentaires

La méthode valueObs.subscribe n'est pas du tout appelée. La méthode getValue (). Subscribe n'est pas non plus appelée.



0
votes
this.socialService.getValue().subscribe(data=>{
    console.log('Trigger from ComponentB');
    console.log(data);
  });

4 commentaires

J'ai essayé cela aussi, ne fonctionnant pas. Y a-t-il autre chose que je pourrais manquer?


au lieu d'appeler un appel constructor () dans ngOnInit


Stackblitz mis à jour


Si vous souhaitez partager des données entre des composants dans Tab. Mieux vaut enregistrer les données dans le stockage local et accéder à d'autres endroits.



6
votes

Vous pouvez effectivement utiliser Subject avec le routeur. Donc, Ici est une solution en direct pour votre scénario en utilisant Routeur et Subject .

Votre service contiendra simplement -

this.socialService.getValue().subscribe(data => {
    this.dataFromB = data;
    console.log('Trigger from ComponentB');
    console.log(data);
})

Ensuite, votre ComponentB contiendra -

buttonClick() {
    this.socialService.setValue("linked successfully");
    this.router.navigate(['/a']);
}

Et, le constructeur de votre ComponentA contiendra -

public setValue(value: string): void {
    this.valueObs.next(value);
}

public getValue(): Observable < string > {
    return this.valueObs;
}

0 commentaires

3
votes

Je pense que vous auriez besoin d'un ReplaySubject pour cela. Votre composant qui s'abonne à l'observable s'abonne, une fois la valeur émise et donc l'observable n'émet plus, il n'y a aucune valeur à obtenir de cette observable. Un ReplaySubject prend soin de donner à l'abonné toutes les émissions qui ont eu lieu avant même la fin de l'abonnement.

La solution @Tushar Walzade fonctionne, car les deux composants sont dans le composant d'application, donc les deux observateurs s'abonnent avant que l'événement ne soit émis. (L'abonnement a lieu à l'intérieur du constructeur pour les deux composants, qui est appelé avant de cliquer sur le bouton). Mais si vous avez un module chargé paresseusement par exemple, le seul composant ne sera créé qu'au chargement et vous n'obtiendrez les données que si vous utilisez un ReplaySubject ou l'opérateur rxjs publier ou partager

Regardez ici:

opérateurs de publication et de partage sujets, sujets de comportement et sujets de relecture


1 commentaires

Votre commentaire vient de sauver ma journée. Merci!



0
votes

Si je ne me trompe pas, ce dont vous avez besoin est soit de souscrire , soit d'utiliser le tube async dans le modèle du composant a afin que vous obteniez toujours la dernière valeur du flux observable.

J'ai créé une application simple pour vous le démontrer.

Disons que nous avons 2 routes, chacune rendant le composant pertinent (a, b).

Nous utilisons un service pour partager des données entre deux composants.

@Component({
  selector: 'b-component',
  template: `Component B <br> 
  <input type="text" placeholder="set data for component a" [(ngModel)]="modifiedData" (ngModelChange)="editServiceData($event)"/>`,
})
export class BComponent  {
  @Input() name: string;
  modifiedData;

  constructor(private myService: MyService) {}

  editServiceData(data: string) {
    this.myService.setValue(data)
  }
}

Ensuite, dans le composant a, nous écoutons les changements du flux observable du service.

@Component({
  selector: 'a-component',
  template: `Component A <br> Data: <pre>{{data}}</pre>`,
})
export class AComponent {
  @Input() name: string;

  data: Observable<string>;

  constructor(private myService: MyService) {
    this.myService.data.subscribe(data => this.data = data);
  }


0 commentaires

0
votes

Le problème est dans votre service. Lorsque vous définissez les données, le sujet a déjà émis la valeur. Faites comme ça.

  1. Dans votre service, rendez BehaviorSubject public et vous n'avez plus besoin de la méthode getValue .

  2. Dans ComponetA où vous recevez les données de CompoenetB , souscrivez à BehaviorSubject qui est valueObs .

Classe de service modifiée comme suit.

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable()
export class SocialService {

  public valueObs: BehaviorSubject<string> = new BehaviorSubject<string>(null);

  constructor() {}

  public setValue(value: string):void {
     this.valueObs.next(value);
     // this.getValue();
  }

 // public getValue():Observable<string> {
 //     return this.valueObs;
 // }
}


0 commentaires