web-dev-qa-db-fra.com

Comment appeler une autre fonction de composants dans angular2

J'ai deux composants comme suit et je veux appeler une fonction d'un autre composant. Les deux composants sont inclus dans le troisième composant parent via directive.

Composant 1:

@component(
selector:'com1'
)
export class com1{
function1(){...}
}

Composante 2:

@component(
selector:'com2'
)
export class com2{
function2(){...
// i want to call function 1 from com1 here
}
}

J'ai essayé d'utiliser @input et @output mais je ne comprends pas exactement comment l'utiliser et comment appeler cette fonction. Quelqu'un peut-il aider?

112
noobProgrammer

Si com1 et com2 sont frères et soeurs, vous pouvez utiliser

@component({
  selector:'com1',
})
export class com1{
  function1(){...}
}

com2 émet un événement à l'aide d'un EventEmitter

@component({
  selector:'com2',
  template: `<button (click)="function2()">click</button>`
)
export class com2{
  @Output() myEvent = new EventEmitter();
  function2(){...
    this.myEvent.emit(null)
  }
}

Ici, le composant parent ajoute une liaison d'événement pour écouter les événements myEvent, puis appelle com1.function1() lorsqu'un tel événement se produit. #com1 est une variable de modèle qui permet de faire référence à cet élément depuis un autre endroit du modèle. Nous l'utilisons pour faire de function1() le gestionnaire d'événements pour myEvent de com2:

@component({
  selector:'parent',
  template: `<com1 #com1></com1><com2 (myEvent)="com1.function1()"></com2>`
)
export class com2{
}

Pour d'autres options de communication entre composants, voir aussi composant-interaction

102

Vous pouvez accéder à la méthode de composant one à partir du composant deux.

composantOne

  ngOnInit() {}

  public testCall(){
    alert("I am here..");    
  }

composantDeux

import { oneComponent } from '../one.component';


@Component({
  providers:[oneComponent ],
  selector: 'app-two',
  templateUrl: ...
}


constructor(private comp: oneComponent ) { }

public callMe(): void {
    this.comp.testCall();
  }

composantDeux fichiers html

<button (click)="callMe()">click</button>
63
Jayantha

Tout d’abord, vous devez comprendre les relations entre les composants. Ensuite, vous pouvez choisir le bon mode de communication. Je vais essayer d’expliquer toutes les méthodes que je connais et que j’utilise dans ma pratique pour la communication entre composants.

Quels types de relations entre composants peuvent-il exister?

1. Parent> Enfant

enter image description here

Partage de données via une entrée

C'est probablement la méthode la plus courante de partage de données. Cela fonctionne en utilisant le décorateur @Input() pour permettre aux données d'être transmises via le modèle.

parent.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'parent-component',
  template: `
    <child-component [childProperty]="parentProperty"></child-component>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent{
  parentProperty = "I come from parent"
  constructor() { }
}

child.component.ts

import { Component, Input } from '@angular/core';

@Component({
  selector: 'child-component',
  template: `
      Hi {{ childProperty }}
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  @Input() childProperty: string;

  constructor() { }

}

C'est une méthode très simple. C'est facile a utiliser. Nous pouvons également détecter les modifications apportées aux données dans le composant enfant à l'aide de ngOnChanges .

Mais n'oubliez pas que si nous utilisons un objet en tant que données et en modifions les paramètres, sa référence ne changera pas. Par conséquent, si nous voulons recevoir un objet modifié dans un composant enfant, il doit être immuable.

2. Enfant> Parent

enter image description here

Partage de données via ViewChild

ViewChild permet à un composant d'être injecté dans un autre, donnant ainsi au parent un accès à ses attributs et fonctions. Un inconvénient, cependant, est que child ne sera disponible qu’après l’initialisation de la vue. Cela signifie que nous devons implémenter le hook AfterViewInit Lifecycle pour recevoir les données de l'enfant.

parent.component.ts

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from "../child/child.component";

@Component({
  selector: 'parent-component',
  template: `
    Message: {{ message }}
    <child-compnent></child-compnent>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent implements AfterViewInit {

  @ViewChild(ChildComponent) child;

  constructor() { }

  message:string;

  ngAfterViewInit() {
    this.message = this.child.message
  }
}

child.component.ts

import { Component} from '@angular/core';

@Component({
  selector: 'child-component',
  template: `
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  message = 'Hello!';

  constructor() { }

}

Partage de données via Output () et EventEmitter

Une autre façon de partager des données consiste à émettre des données de l'enfant, qui peuvent être répertoriées par le parent. Cette approche est idéale lorsque vous souhaitez partager des modifications de données qui se produisent sur des éléments tels que les clics sur les boutons, les entrées de formulaire et d'autres événements utilisateur.

parent.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'parent-component',
  template: `
    Message: {{message}}
    <child-component (messageEvent)="receiveMessage($event)"></child-component>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {

  constructor() { }

  message:string;

  receiveMessage($event) {
    this.message = $event
  }
}

child.component.ts

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'child-component',
  template: `
      <button (click)="sendMessage()">Send Message</button>
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  message: string = "Hello!"

  @Output() messageEvent = new EventEmitter<string>();

  constructor() { }

  sendMessage() {
    this.messageEvent.emit(this.message)
  }
}

3. Frères et sœurs

enter image description here

Enfant> Parent> Enfant

J'essaie d'expliquer d'autres moyens de communiquer entre frères et soeurs ci-dessous. Mais vous pouviez déjà comprendre l’un des moyens de comprendre les méthodes ci-dessus.

parent.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'parent-component',
  template: `
    Message: {{message}}
    <child-one-component (messageEvent)="receiveMessage($event)"></child1-component>
    <child-two-component [childMessage]="message"></child2-component>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {

  constructor() { }

  message: string;

  receiveMessage($event) {
    this.message = $event
  }
}

child-one.component.ts

import { Component, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'child-one-component',
  template: `
      <button (click)="sendMessage()">Send Message</button>
  `,
  styleUrls: ['./child-one.component.css']
})
export class ChildOneComponent {

  message: string = "Hello!"

  @Output() messageEvent = new EventEmitter<string>();

  constructor() { }

  sendMessage() {
    this.messageEvent.emit(this.message)
  }
}

child-two.component.ts

import { Component, Input } from '@angular/core';

@Component({
  selector: 'child-two-component',
  template: `
       {{ message }}
  `,
  styleUrls: ['./child-two.component.css']
})
export class ChildTwoComponent {

  @Input() childMessage: string;

  constructor() { }

}

4. Composants non liés

enter image description here

Toutes les méthodes décrites ci-dessous peuvent être utilisées pour toutes les options ci-dessus pour la relation entre les composants. Mais chacun a ses avantages et ses inconvénients.

Partage de données avec un service

Lorsque vous transmettez des données entre des composants dépourvus de connexion directe, tels que des frères et soeurs, des petits-enfants, etc., vous devez disposer d'un service partagé. Lorsque vous avez des données qui devraient toujours être synchronisées, je trouve le BehaviorSubject de RxJS très utile dans cette situation.

data.service.ts

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

@Injectable()
export class DataService {

  private messageSource = new BehaviorSubject('default message');
  currentMessage = this.messageSource.asObservable();

  constructor() { }

  changeMessage(message: string) {
    this.messageSource.next(message)
  }

}

first.component.ts

import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";

@Component({
  selector: 'first-componennt',
  template: `
    {{message}}
  `,
  styleUrls: ['./first.component.css']
})
export class FirstComponent implements OnInit {

  message:string;

  constructor(private data: DataService) {
      // The approach in Angular 6 is to declare in constructor
      this.data.currentMessage.subscribe(message => this.message = message);
  }

  ngOnInit() {
    this.data.currentMessage.subscribe(message => this.message = message)
  }

}

second.component.ts

import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";

@Component({
  selector: 'second-component',
  template: `
    {{message}}
    <button (click)="newMessage()">New Message</button>
  `,
  styleUrls: ['./second.component.css']
})
export class SecondComponent implements OnInit {

  message:string;

  constructor(private data: DataService) { }

  ngOnInit() {
    this.data.currentMessage.subscribe(message => this.message = message)
  }

  newMessage() {
    this.data.changeMessage("Hello from Second Component")
  }

}

Partage de données avec une route

Parfois, vous devez non seulement transmettre des données simples entre composants, mais également enregistrer un certain état de la page. Par exemple, nous souhaitons enregistrer certains filtres sur le marché en ligne, puis copier ce lien et les envoyer à un ami. Et nous nous attendons à ce qu'il ouvre la page dans le même état que nous. Le premier moyen, et probablement le plus rapide, de le faire serait d'utiliser paramètres de requête .

Les paramètres de requête ressemblent davantage à ceux de /people?id=id peut être égal à n'importe quoi et vous pouvez avoir autant de paramètres que vous le souhaitez. Les paramètres de la requête seraient séparés par le caractère esperluette.

Lorsque vous travaillez avec des paramètres de requête, vous n’avez pas besoin de les définir dans votre fichier d’itinéraires. Vous pouvez les nommer paramètres. Par exemple, prenons le code suivant:

page1.component.ts

import {Component} from "@angular/core";
import {Router, NavigationExtras} from "@angular/router";

@Component({
    selector: "page1",
  template: `
    <button (click)="onTap()">Navigate to page2</button>
  `,
})
export class Page1Component {

    public constructor(private router: Router) { }

    public onTap() {
        let navigationExtras: NavigationExtras = {
            queryParams: {
                "firstname": "Nic",
                "lastname": "Raboy"
            }
        };
        this.router.navigate(["page2"], navigationExtras);
    }

}

Dans la page de réception, vous recevriez ces paramètres de requête, comme suit:

page2.component.ts

import {Component} from "@angular/core";
import {ActivatedRoute} from "@angular/router";

@Component({
    selector: "page2",
    template: `
         <span>{{firstname}}</span>
         <span>{{lastname}}</span>
      `,
})
export class Page2Component {

    firstname: string;
    lastname: string;

    public constructor(private route: ActivatedRoute) {
        this.route.queryParams.subscribe(params => {
            this.firstname = params["firstname"];
            this.lastname = params["lastname"];
        });
    }

}

NgRx

Le dernier moyen, plus compliqué mais plus puissant, consiste à utiliser NgRx . Cette bibliothèque n'est pas pour le partage de données; c'est une puissante bibliothèque de gestion d'état. Dans un court exemple, je ne peux pas expliquer comment l'utiliser, mais vous pouvez aller sur le site officiel et lire la documentation à ce sujet.

Pour moi, NgRx Store résout plusieurs problèmes. Par exemple, lorsque vous devez gérer des éléments observables et lorsque la responsabilité de certaines données observables est partagée entre différents composants, les actions de la banque d'informations et le réducteur garantissent que les modifications des données seront toujours effectuées "de la bonne manière".

Il fournit également une solution fiable pour la mise en cache des demandes HTTP. Vous pourrez stocker les demandes et leurs réponses afin de vérifier que la demande que vous faites n'a pas encore de réponse stockée.

Vous pouvez en savoir plus sur NgRx et savoir si vous en avez besoin ou non dans votre application:

Enfin, je tiens à dire qu'avant de choisir certaines méthodes de partage de données, vous devez comprendre comment ces données seront utilisées à l'avenir. Je veux dire que peut-être que vous pouvez utiliser juste un décorateur @Input pour partager un nom d'utilisateur et un nom de famille. Ensuite, vous ajouterez un nouveau composant ou un nouveau module (un panneau d’administration, par exemple) qui nécessite davantage d’informations sur l’utilisateur. Cela signifie que cela peut être un meilleur moyen d'utiliser un service pour les données utilisateur ou un autre moyen de partager des données. Vous devez y penser davantage avant de commencer à mettre en œuvre le partage de données.

60
Roman Skydan

Cela dépend de la relation entre vos composants (parent/enfant), mais le meilleur moyen générique de faire communiquer les composants est d'utiliser un service partagé.

Voir cette doc pour plus de détails:

Ceci étant dit, vous pouvez utiliser ce qui suit pour fournir une instance du com1 dans com2:

<div>
  <com1 #com1>...</com1>
  <com2 [com1ref]="com1">...</com2>
</div>

Dans com2, vous pouvez utiliser les éléments suivants:

@Component({
  selector:'com2'
})
export class com2{
  @Input()
  com1ref:com1;

  function2(){
    // i want to call function 1 from com1 here
    this.com1ref.function1();
  }
}
25
Thierry Templier

Composant 1 (enfant):

@Component(
  selector:'com1'
)
export class Component1{
  function1(){...}
}

Composant 2 (parent):

@Component(
  selector:'com2',
  template: `<com1 #component1></com1>`
)
export class Component2{
  @ViewChild("component1") component1: Component1;

  function2(){
    this.component1.function1();
  }
}
25
Ihor Khomiak
  • Disons que le 1er composant est DbstatsMainComponent
  • 2ème composant DbstatsGraphComponent.
  • 1er composant appelant la méthode de 2nd

<button (click)="dbgraph.displayTableGraph()">Graph</button> <dbstats-graph #dbgraph></dbstats-graph>

Notez la variable locale #dbgraph sur le composant enfant, que le parent peut utiliser pour accéder à ses méthodes (dbgraph.displayTableGraph()).

1
RAHUL KUMAR

En utilisant Dataservice, nous pouvons appeler la fonction depuis un autre composant

Composant1: Le composant dont nous appelons la fonction

constructor( public bookmarkRoot: dataService ) { } 

onClick(){
     this.bookmarkRoot.callToggle.next( true );
}

dataservice.ts

import { Injectable } from '@angular/core';
@Injectable()
export class dataService {
     callToggle = new Subject();
}

Composant2: Le composant qui contient la fonction

constructor( public bookmarkRoot: dataService ) { 
  this.bookmarkRoot.callToggle.subscribe(( data ) => {
            this.closeDrawer();
        } )
} 

 closeDrawer() {
        console.log("this is called")
    }
0
Shafeeq Mohammed