Подтвердить что ты не робот

Функция обратного вызова углового прохода для дочернего компонента как @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>
4b9b3361

Ответ 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 вещи здесь:

  1. Толстая стрелка (=>) работает вместо .bind(this) для хранения правильного контекста;
  2. Безопасное объявление функции обратного вызова в дочернем компоненте.

Ответ 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; 
  ...
}