Interactions avec les composants enfants
Objectifs de la partie
Apprendre à faire passer des données entre les composants
Contexte :
Bien souvent, nous avons besoin de faire passer des informations entre un composant et ses enfants.
Méthode :
Nous avons vu qu'un composant Angular peut être composé d'autre composants. Cette approche est intéressante par nature mais le devient encore plus dès lors que l'on peut échanger des informations entre un parent et son enfant.
Passage d'informations à l'enfant @Input
.
Le décorateur @Input
permet de déclarer qu'un composant attend des informations en entrée. Il se place sur une propriété du composant et indique que celle-ci est bindée sur une propriété de son parent. Le parent doit renseigner cette propriété sous forme d'attribut du sélecteur. Une modification de la propriété d'origine dans le parent déclenche une modification de la propriété bindée de l'enfant.
Admettons que l'on désire afficher des news sur l'accueil de notre application. Nous créons donc un composant news-item
représentant l'affichage d'une news. Le composant app
va donc utiliser ce composant news-item (créant ainsi une relation parent-enfant). C'est bien le composant app
qui va récupérer et contenir la liste de news et leur détail. Il va donc falloir que celui-ci passe les informations sur chacune des news au composant news-item
.
@Component({
selector: 'sty-news-item',
templateUrl: './news-item.component.html'
})
export class NewsItemComponent {
@Input()
public title: string;
@Input()
public content: string;
}
Le composant news-item
possède deux propriétés : title
et content
. Ces propriétés sont annotées @Input
, cela indique qu'elles sont attendues en entrée du composant. Le template d'une news est relativement simple et contient juste l'affichage du titre et du contenu :
<h3>{{ title }}</h3>
<p>{{ content }}</p>
Pour passer les paramètres title
et news
, le composant app
utilise la syntaxe suivante :
<p>Flash info, dernières nouvelles :</p>
<div *ngFor="let news of newsList">
{{ news.title }}
<sty-news-item title="{{ news.title }}" content="{{ news.content }}"></sty-news-item>
</div>
Il parcourt la liste de news qu'il contient grâce à sa propriété newsList
. Et pour chaque news, il crée une instance du composant news-item
pour afficher ses informations.
Il est aussi tout à fait possible de passer des valeurs fixes en paramètre :
<sty-news-item title="Hello" content="World"></sty-news-item>
Passage d'informations au parent @Output
.
Un composant enfant peut aussi avoir besoin de passer des informations ou un événement à son parent afin qu'il effectue des actions. Cette organisation du code permet de rendre les composants plus génériques et indépendants. Cette transmission d'informations se fait grâce au décorateur @Output
.
Reprenons l'exemple de notre affichage de news. Nous voulons maintenant pouvoir notifier le composant app
au clic sur un bouton afin qu'il ajoute un smiley au titre.
@Component({
selector: 'sty-news-item',
templateUrl: './news-item.component.html'
})
export class NewsItemComponent {
@Input()
public title: string;
@Input()
public content: string;
@Output()
private smileyClick = new EventEmitter<any>();
appendSmiley() {
this.smileyClick.emit(this.title);
}
}
Vous remarquerez que @Output
s'utilise sur une propriété de type EventEmitter
et qu'il faut appeler la méthode .emit()
pour déclencher l'événement.
<h3>{{ title }}</h3>
<p>{{ content }}</p>
<button (click)="appendSmiley()">Ajouter smiley</button>
Le clic sur le bouton « Ajouter smiley » provoque l'appel à la méthode du news-item, celle-là même qui utilise le .emit()
et déclenche l'événement.
<p>Flash info, dernières nouvelles :</p>
<div *ngFor="let news of newsList">
{{ news.title }}
<sty-news-item title="{{ news.title }}" content="{{ news.content }}" (smileyClick)="appendSmiley($event)"></sty-news-item>
</div>
On utilise ensuite (smileyClick)=”<
, méthode du parent permettant de traiter l’événement >”
pour récupérer et traiter l'événement émis par l'enfant.
@Component({
selector: 'sty-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'angular-basics';
public newsList = [
new News('Météo - Demain', 'Il fait beau demain.'),
new News('Météo - Apres demain', 'Il fait beau après demain !'),
new News('Attention', 'Problème de contrôle')
];
appendSmiley($title: string) {
this.newsList.find(news => news.title === $title).title += ' :)';
}
}
Enfin, la méthode appendSmiley
du parent a la charge d'ajouter un smiley à la fin du titre de la news concernée, retrouvée ici grâce à son titre passé par l'enfant dans l'événement.
Syntaxe : À retenir
@Input
,@Output
,<childComponent attributInput=”valeur” (attributOutput)=”
méthode de traitement de l’événement”>
.