AngularJS a les paramètres & où vous pouvez passer un callback à une directive (par exemple façon de callback AngularJS . Est-il possible de passer un callback en tant que @Input
pour un Angular Composant (quelque chose comme ci-dessous)? Sinon, quelle serait la chose la plus proche de ce que fait AngularJS?
@Component({
selector: 'suggestion-menu',
providers: [SuggestService],
template: `
<div (mousedown)="suggestionWasClicked(suggestion)">
</div>`,
changeDetection: ChangeDetectionStrategy.Default
})
export class SuggestionMenuComponent {
@Input() callback: Function;
suggestionWasClicked(clickedEntry: SomeModel): void {
this.callback(clickedEntry, this.query);
}
}
<suggestion-menu callback="insertSuggestion">
</suggestion-menu>
Je pense que c'est une mauvaise solution. Si vous souhaitez passer une fonction dans un composant avec @Input()
, @Output()
décorateur est ce que vous recherchez.
export class SuggestionMenuComponent {
@Output() onSuggest: EventEmitter<any> = new EventEmitter();
suggestionWasClicked(clickedEntry: SomeModel): void {
this.onSuggest.emit([clickedEntry, this.query]);
}
}
<suggestion-menu (onSuggest)="insertSuggestion($event[0],$event[1])">
</suggestion-menu>
UPDATE
Cette réponse a été soumise alors que Angular 2 était encore en alpha et que de nombreuses fonctionnalités n'étaient pas disponibles/non documentées. Bien que le programme ci-dessous fonctionne toujours, cette méthode est maintenant totalement obsolète. Je fortement recommande la réponse acceptée par rapport à celle ci-dessous.
Réponse originale
Oui, c’est vrai, mais vous voudrez vous assurer qu’elle est correctement définie. Pour cela, j'ai utilisé une propriété pour m'assurer que this
signifie ce que je veux.
@Component({
...
template: '<child [myCallback]="theBoundCallback"></child>',
directives: [ChildComponent]
})
export class ParentComponent{
public theBoundCallback: Function;
public ngOnInit(){
this.theBoundCallback = this.theCallback.bind(this);
}
public theCallback(){
...
}
}
@Component({...})
export class ChildComponent{
//This will be bound to the ParentComponent.theCallback
@Input()
public myCallback: Function;
...
}
Une alternative à la réponse donnée par SnareChops.
Vous pouvez utiliser .bind (this) dans votre modèle pour avoir le même effet. Ce n'est peut-être pas aussi propre mais cela économise quelques lignes. Je suis actuellement sur angular 2.4.0
@Component({
...
template: '<child [myCallback]="theCallback.bind(this)"></child>',
directives: [ChildComponent]
})
export class ParentComponent {
public theCallback(){
...
}
}
@Component({...})
export class ChildComponent{
//This will be bound to the ParentComponent.theCallback
@Input()
public myCallback: Function;
...
}
Dans certains cas (rares), vous aurez peut-être besoin que la logique métier soit exécutée par un composant parent. Dans l'exemple ci-dessous, nous avons un composant enfant qui rend la ligne d'un tableau en fonction de la logique fournie par le composant parent:
@Component({
...
template: '<table-component [getRowColor]="getColor"></table-component>',
directives: [TableComponent]
})
export class ParentComponent {
// Pay attention on the way this function is declared. Using fat arrow (=>) declaration
// we can 'fixate' the context of `getColor` function
// so that it is bound to ParentComponent as if .bind(this) was used.
getColor = (row: Row) => {
return this.fancyColorService.getUserFavoriteColor(row);
}
}
@Component({...})
export class TableComponent{
// This will be bound to the ParentComponent.getColor.
// I found this way of declaration a bit safer and convenient than just raw Function declaration
@Input('getRowColor') getRowColor: (row: Row) => Color;
renderRow(){
....
// Notice that `getRowColor` function holds parent's context because of a fat arrow function used in the parent
const color = this.getRowColor(row);
renderRow(row, color);
}
}
Peut-être que ce n'est pas un cas idéal et que cela peut être fait d'une meilleure façon, mais je voulais simplement démontrer deux choses ici:
Méthode de passage avec argument, utilisant .bind à l'intérieur du modèle
@Component({
...
template: '<child [action]="foo.bind(this, 'someArgument')"></child>',
...
})
export class ParentComponent {
public foo(someParameter: string){
...
}
}
@Component({...})
export class ChildComponent{
@Input()
public action: Function;
...
}
Par exemple, j'utilise une fenêtre modale de connexion, où la fenêtre modale est le parent, le formulaire de connexion est l'enfant et le bouton de connexion rappelle la fonction de fermeture du parent modal.
Le modal parent contient la fonction permettant de fermer le modal. Ce parent transmet la fonction de fermeture au composant enfant de connexion.
import { Component} from '@angular/core';
import { LoginFormComponent } from './login-form.component'
@Component({
selector: 'my-modal',
template: `<modal #modal>
<login-form (onClose)="onClose($event)" ></login-form>
</modal>`
})
export class ParentModalComponent {
modal: {...};
onClose() {
this.modal.close();
}
}
Une fois que le composant de connexion enfant a soumis le formulaire de connexion, il ferme le modal parent à l'aide de la fonction de rappel du parent.
import { Component, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'login-form',
template: `<form (ngSubmit)="onSubmit()" #loginForm="ngForm">
<button type="submit">Submit</button>
</form>`
})
export class ChildLoginComponent {
@Output() onClose = new EventEmitter();
submitted = false;
onSubmit() {
this.onClose.emit();
this.submitted = true;
}
}