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>

当前回答

以下是我在Angular 13中的工作(截至2022年3月)。

附注:这与其他人的回答或多或少有些相似。添加这个答案只是为了让人们知道它可以在Angular 13中工作。

在父组件中将函数定义为平箭头函数,而不是常规函数。

callBackFn= (args: string): void => {
  // callback code here
  // This will work (Flat Arrow)
}
// callbackFn(args: string): void {
//   //This type of definition will not work.
// }

将回调函数作为属性传递给子组件

<app-child [callBack]=”callBackFn”></app-child>

在子组件中接收回调函数作为Input。该定义应该与父类中定义的定义相匹配。

@Input() callBack: (args: string) => void;

然后在子组件中调用该函数。你也可以称它为子组件模板。

this.callBack('Test');

OR

<button (click)="callBack('Test')"></button>

但不确定这种方法是否好。 我在ReactJS中看到了类似的方法,它工作得很好,但仍然不确定它在angular中是如何工作的,以及它的影响是什么。

请对这一办法提出任何意见。

其他回答

在某些情况下,您可能需要由父组件执行业务逻辑。在下面的例子中,我们有一个子组件,它根据父组件提供的逻辑来呈现表行:

@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);
  }
}

所以,我想在这里演示两件事:

胖箭头(=>)代替.bind(this)来保存正确的上下文; 子组件中回调函数的类型安全声明。

目前的答案可以简化为……

@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; 
  ...
}

以下是我在Angular 13中的工作(截至2022年3月)。

附注:这与其他人的回答或多或少有些相似。添加这个答案只是为了让人们知道它可以在Angular 13中工作。

在父组件中将函数定义为平箭头函数,而不是常规函数。

callBackFn= (args: string): void => {
  // callback code here
  // This will work (Flat Arrow)
}
// callbackFn(args: string): void {
//   //This type of definition will not work.
// }

将回调函数作为属性传递给子组件

<app-child [callBack]=”callBackFn”></app-child>

在子组件中接收回调函数作为Input。该定义应该与父类中定义的定义相匹配。

@Input() callBack: (args: string) => void;

然后在子组件中调用该函数。你也可以称它为子组件模板。

this.callBack('Test');

OR

<button (click)="callBack('Test')"></button>

但不确定这种方法是否好。 我在ReactJS中看到了类似的方法,它工作得很好,但仍然不确定它在angular中是如何工作的,以及它的影响是什么。

请对这一办法提出任何意见。

与Max Fahl给出的答案不同。

你可以将回调函数定义为父组件中的箭头函数,这样你就不需要绑定它了。

@Component({
  ...
  // unlike this, template: '<child [myCallback]="theCallback.bind(this)"></child>',
  template: '<child [myCallback]="theCallback"></child>',
  directives: [ChildComponent]
})
export class ParentComponent {

   // unlike this, public theCallback(){
   public theCallback = () => {
    ...
  }
}

@Component({...})
export class ChildComponent{
  //This will be bound to the ParentComponent.theCallback
  @Input()
  public myCallback: Function; 
  ...
}

我认为这是一个糟糕的解决方案。如果你想通过@Input()将Function传递给组件,@Output()装饰器就是你要找的。

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>