0
votes

Angular7 child1 to parent - erreur de communication parent-enfant2

juste un exemple pour mon problème: - Le parent a child1 et child2.

Je montre une liste de mois dans un tableau, onLoad de child2.

en cliquant sur les boutons à child1, les mois seront pop n push.

en cliquant sur un bouton sur child1, il émet une nouvelle valeur au parent et plus loin cette valeur ira du parent à child2.ts et mettre à jour le tableau du mois

Le problème est que j'obtiens une erreur lors de la communication du parent à child2. J'ai utilisé la méthode d'abonnement observable et elle dit

////////////// parent.html//////////////////////////////////////////
< child2 class="row-items" [navigatedMonths]="months">< /child2>
< child1(navigateMonths)='navigatedMonths($event)'> Next Month< /child1>

Voici mon code.

////////////////child1.ts///////////////////////////////////

onClick() {
  this.navigateMonths.emit(this.month);
}



////////////// parent.ts//////////////////////
months: Subject < void > = new Subject < void > ();
navigatedMonths(months) {
  this.months = months;
  this.months.asObservable();
}

/////////child2.ts////////////////////////
@Input() navigatedMonths: Observable < void > ;
ngOnInit() {
  this.navigatedMonths.subscribe((months) => {
    this.months = months;
  })
  this.getMonths(this.year, this.month);

}
this.months.asObservable is not a function


0 commentaires

3 Réponses :


1
votes

quickfix - se débarrasser des observables / sujets qui ne sont pas nécessaires

export class MonthsService {

  // private for internal use
  private monthsSource: BehaviorSubject<string[]> = new BehaviorSubject([]); // init with empty array

  // public for use in components or other services
  months$: Observable<string[]> = this.monthsSource.asObservable(); 

  addMonth(newMonth: string) {
    const months = [...this.monthsSource.getValue(), newMonth]; // Create new months array
    this.monthsSource.next(months);
  }
}

Vous devriez probablement envisager d'introduire un service qui est partagé entre les deux enfants. Le parent n'a pas besoin de connaître les mois.

Lisez ceci: https://angular.io/guide/component-interaction ( Le parent et les enfants communiquent via un service ) - il en va de même pour la communication entre les composants (même s'ils n'ont pas de relation parent-enfant)

Le service pourrait ressembler comme ceci:

////////////// parent.ts//////////////////////
months: any[]; // no subject anymore
navigatedMonths(months) {
  this.months = months;
}

/////////child2.ts////////////////////////
@Input() 
set navigatedMonths(months: any[]) { // make a setter from your input
   // Do whatever you want when new months come in
} 

Exemple complet: https://stackblitz.com/edit/ng-zorro-antd-start-ddozvn

Maintenant, les fils n'ont plus d'entrées ou de sorties, le composant parent reste propre. Chaque composant qui s'intéresse aux données s'abonne simplement aux mois $ observable.


4 commentaires

Comment dois-je le réparer? Je suis confus maintenant


navigatedMonths (mois) {this.months = mois; this.months.asObservable (); /////// c'est une erreur}


Ahhh je vois. this.months n'est pas un sujet observable à ce stade. .asObservable ne fonctionne que sur les sujets


Je viens d'ajouter la solution à ma réponse qui utilise un service de conservation des données des mois



1
votes

Le scénario que vous avez mentionné peut être réalisé en émettant des données de child1 vers parent (en utilisant eventEmitters)

enfant1.ts

ngOnInit(){
   this.myService.mySubject.subscribe((data)=>{
     this.months.push(data);
     console.log(this.months);
   });
}

puis de parent à enfant2 (en utilisant @viewChild).

parent.ts

this.myService.mySubject.next(this.months[this.i++])

enfant2.ts

mySubject = new Subject();

Démo de travail ajoutée: démo

Remarque : la sortie du tableau des mois de child2 peut être vue sur la console.

Modifier: Suite est la deuxième méthode utilisant Subject dans service . Cette méthode peut être utilisée pour tous les types d'interactions de composants. Qu'il s'agisse d'interactions parent-enfant ou enfant-parent ou frères et sœurs .

Vous devez suivre les étapes suivantes: p>

myService.ts

Créer un sujet en service. (Le sujet doit être importé de rxjs)

  months:any[] = [];
  @Input() childMessage: string;
  addMonth(month){
     this.months.push(month);
     console.log(this.months);
  }

enfant1.ts

Ajouter / envoyer un élément au sujet en utilisant next():

  message:string;
  @ViewChild(Child2Component) child;
  receiveMessage($event) {
     this.message = $event
     this.child.addMonth(this.message);
  }

enfant2.ts

Abonnez-vous à Subject pour lire l'élément:

  i = 0;
  months = ["jan","feb","march","april"];
  @Output() messageEvent = new EventEmitter<string>();
  sendMessage() {
     this.messageEvent.emit(this.months[this.i]);
     this.i++;
  }


4 commentaires

Pouvez-vous l'expliquer? C'est intéressant mais pas capable de comprendre comment cela fonctionne pour un parent à enfant2


@developer ViewChild permet à un composant d'être injecté dans un autre, donnant au parent l'accès à ses attributs et fonctions. Donc, avec la référence child2 dans le parent, j'appelle sa fonction addMonth () pour ajouter des mois au tableau de child2.


Pouvons-nous le faire en utilisant un abonnement? Le développeur principal a dit que vous utilisiez parentcomponent.childComponent.childFunction (), ce qui n'est pas la bonne approche


vous devriez vraiment lire ceci: angular.io/guide/component-interaction :) Cette page aussi montre la solution Himanshu Singh comme possibilité. Mais comme mentionné dans ma réponse, je préférerais opter pour la solution de service (où le service contient un sujet de mois et quel que soit le composant qui l'intéresse, il peut y souscrire). Votre aîné sera heureux;)



0
votes

Une autre option consiste à utiliser la liaison bidirectionnelle avec @Input () , @Output () et EventEmitter . En donnant à votre @Output () EventEmitter le même nom que vous @Input () et en ajoutant Change au name, vous pouvez obtenir une liaison bidirectionnelle.

child1.component.ts

<app-child1 [(message)]="message"></app-child1>
<app-child2 [(message)]="message"></app-child2>

parent.component.html

@Input()
public message: Message;

@Output()
public messageChange: EventEmitter<Message> = new EventEmitter<Message>();

public text: string;

send() {
  if (this.text.trim().length > 0) {
    this.messageChange.emit(new Message(`Child1: ${this.text}`));
  }
}

https://stackblitz.com/edit/angular-46ndlt

https://medium.com/ @ preethi.s / angular-custom-two-way-data-binding-3e618309d6c7


0 commentaires