Angular2: Passing an object to bind event from parent to child

与世无争的帅哥 提交于 2019-12-11 08:17:51

问题


The binding works fine for title, subtitle, button.icon and button.name but not for button.action

parent.component.html

    <app-title [title]="title" [subtitle]="subtitle" [buttons]="buttons"></app-title>

parent.component.ts

export class ParentComponent {

actionOne() {
    ...
}

title = 'Title';
subtitle = 'Subtitle';
buttons = [
    { 'name': 'Name1', 'icon': 'Icon1', 'action': 'actionOne()'},
    { 'name': 'Name2', 'icon': 'Icon2', 'action': 'actionTwo()'},
    { 'name': 'Name3', 'icon': 'Icon3', 'action': 'actionThree()'}
];

}

child.component.html

<section>
<div class="text-wrapper">
        <h1>{{ title }}</h1>
        <h2 *ngIf="subtitle">{{ subtitle }}</h2>
</div>
 <template *ngIf="buttons">
        <div class="buttons-wrapper">
            <button *ngFor="let button of buttons" md-raised-button (click)="button.action"><md-icon *ngIf="button.icon">{{ button.icon }}</md-icon>{{ button.name }}</button>
        </div>
    </template>
</div>

child.component.ts

export class ChildComponent  {

@Input() title:string;
@Input() subtitle:string;
@Input() buttons:string;

}


回答1:


This is possible to do:

Button interface:

export interface IButton {
  Name: string;
  Icon: string;
  Action: Function
}

Parent component:

@Component({
...
})
export class ParentComponent implements OnInit {
  buttons: IButton[] = [
    {
      Name: 'Hello',
      Icon: 'Test',
      Action: this.actionOne.bind(this) // we need to make sure this is scoped correctly
    }
  ];

  actionOne(){
    console.log('This is from action One');
  }

  constructor() { }

  ngOnInit() {

  }
}

Child component

@Component({
...
})
export class ChildComponent implements OnInit {
  @Input() buttons: IButton[];

  constructor() { }

  ngOnInit() {

  }
}

Child html

<div *ngIf="buttons">
  <button *ngFor="let button of buttons" (click)="button.Action()">{{button.Name}}</button>
</div>

Hope that helps




回答2:


Your code cannot work, since you are passing string literals, not method references, to the child. For instance, in the button.action property, your ChildComponent sees the string literal "actionOne()", not the method actionOne().

In order to pass the method references when declaring the buttons, you'd have to remove the quotes and parentheses around the method names and prefix them with this.:

buttons = [
    { 'name': 'Name1', 'icon': 'Icon1', 'action': this.actionOne },
    { 'name': 'Name2', 'icon': 'Icon2', 'action': this.actionTwo },
    { 'name': 'Name3', 'icon': 'Icon3', 'action': this.actionThree }
]

But still, it won't work as the context for this will be lost in the ChildComponent.

What I would do is use string literals in the buttons declarations (similar to your code, but WITHOUT the parentheses, e.g. 'actionOne', 'actionTwo'...) and whenever a button is clicked in the child, I would emit an @Output event to the parent:

@Component({
  template: `
    <button (click)="buttonClicked.emit(button.action)">
      {{ button.name }}
    </button>
  `
})
export class ChildComponent  {
  @Output() buttonClicked: EventEmitter<string> = new EventEmitter<string>();
}

Notice that I'm passing the button.action property (string) when emitting the event.

Now, the ParentComponent can listen to that event and use the received string as an identifier to decide which local method to call:

@Component({
  template: `
    <child-comp (buttonClicked)="handleAction($event)"></child-comp>
  `
})
export class ParentComponent  {

  handleAction(actionName) {
    // Here, put some logic to call a local method based on `actionName`
    // Something like this[actionName]();
  }

  actionOne() {
      ...
  }

  actionTwo() {
      ...
  }

}


来源:https://stackoverflow.com/questions/41765839/angular2-passing-an-object-to-bind-event-from-parent-to-child

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!