Функция обратного вызова углового прохода для дочернего компонента как @Input аналогично AngularJS
У AngularJS есть параметры и параметры, где вы могли бы передать обратный вызов директиве (например, метод обратных вызовов AngularJS. Можно ли передать обратный вызов как @Input
для компонента Angular (что-то вроде ниже)? Если не то, что было бы самым близким к тому, что делает 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>
Ответы
Ответ 1
Я думаю, что это плохое решение. Если вы хотите передать функцию в компонент с @Input()
, @Output()
decorator - это то, что вы ищете.
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>
Ответ 2
UPDATE
Этот ответ был отправлен, когда Angular 2 все еще находился в альфе, и многие из функций были недоступны/недокументированы. Хотя ниже все еще будет работать, этот метод теперь полностью устарел. Я сильно рекомендую принятый ответ ниже.
Оригинальный ответ
Да, на самом деле это так, но вы захотите убедиться, что он правильно установлен. Для этого я использовал свойство, чтобы гарантировать, что this
означает, что я хочу.
@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;
...
}
Ответ 3
Альтернатива ответам SnareChops дала.
Вы можете использовать .bind(this) в своем шаблоне, чтобы иметь тот же эффект. Он может быть не таким чистым, но он сохраняет пару строк. Я сейчас на 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;
...
}
Ответ 4
В некоторых случаях вам может потребоваться выполнение бизнес-логики родительским компонентом. В приведенном ниже примере у нас есть дочерний компонент, который отображает строку таблицы в зависимости от логики, предоставленной родительским компонентом:
@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 context because of a fat arrow function used in the parent
const color = this.getRowColor(row);
renderRow(row, color);
}
}
Итак, я хотел продемонстрировать 2 вещи здесь:
- Толстая стрелка (=>) работает вместо .bind(this) для хранения правильного контекста;
- Безопасное объявление функции обратного вызова в дочернем компоненте.
Ответ 5
В качестве примера я использую модовое окно входа в систему, где модальное окно является родительским, форма входа - это дочерний элемент, а кнопка входа в систему возвращает функцию модального родительского закрытия.
Родительский модал содержит функцию для закрытия модальности. Этот родитель передает функцию закрытия дочернему компоненту входа.
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();
}
}
После того, как дочерний компонент входа отправит форму входа, он закрывает родительский модальный метод, используя функцию обратного вызова родителя
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;
}
}
Ответ 6
Передача метода с аргументом, используя .bind внутри шаблона
@Component({
...
template: '<child [action]="foo.bind(this, 'someArgument')"></child>',
...
})
export class ParentComponent {
public foo(someParameter: string){
...
}
}
@Component({...})
export class ChildComponent{
@Input()
public action: Function;
...
}
Ответ 7
Текущий ответ можно упростить, чтобы...
@Component({
...
template: '<child [myCallback]="theCallback"></child>',
directives: [ChildComponent]
})
export class ParentComponent{
public theCallback(){
...
}
}
@Component({...})
export class ChildComponent{
//This will be bound to the ParentComponent.theCallback
@Input()
public myCallback: Function;
...
}