Angular2:如何从子组件调用主组件函数

时间:2017-03-30 02:42:08

标签: angular typescript angular2-directives angular2-components

当我有深层嵌套层次结构时,如何从子组件调用主组件函数?

enter image description here

我有3个组件,按钮组件I包括内部浏览器组件和浏览器组件I,包括内部主组件。

点击按钮我需要调用主要组件内的功能。

按钮组件

@Component({
    selector: 'cb-button',
    templateUrl: 'cb-button.component.html',
    styleUrls: ['cb-button.component.scss']
})

export class CbButtonComponent {

     @Output() onClick: EventEmitter<any> = new EventEmitter();

     onBtnClick(): void {
        this.onClick.emit();
    }
}

按钮组件html

<div (click)="onBtnClick()">
    <button>btn</button>
</div>

浏览器组件

@Component({
    selector: 'topology-browser',
    templateUrl: 'topology-browser.component.html',
    styleUrls: ['topology-browser.component.scss']
})

export class TopologyBrowserComponent {

   @Input('campus') campus: Campus;
}

浏览器组件html

<div>
<h1>browser title</h1>
<cb-button (click)="editCampus()"></cb-button>
</div>

最后在主要组件i中包括浏览器组件

主要-component.ts

editCampus() {
  alert('clicked');
}

HTML

<topology-browser [campus]="campus"></topology-browser>

当我点击按钮时,我得到以下错误

Errorself.parentView.context.editCampus不是函数

4 个答案:

答案 0 :(得分:3)

  • 如果您知道根组件的类型,可以使用Pengyy的方法。
  • 如果您事先不知道哪种类型,但您可以根据需要自定义根组件,那么共享服务是一种好方法。

  • 更通用的方法是通过注入ApplicationRef来获取根组件(实际上没有自己测试过):

constructor(app:ApplicationRef, injector: Injector) {
  app.components[0].someMethodOnMainComponent();
}

PS info reference

答案 1 :(得分:2)

据我所知,您的情况有两种方式:

  • inject子组件的父组件
  • 使用EventEmitter

由于您有两个以上的图层,因此将MainComponent注入ButtonComponent要简单得多:

import {Component, Inject, forwardRef} from '@angular/core';

// change the MainComponent to your real component name
constructor(@Inject(forwardRef(() => MainComponent)) private main:MainComponent)

答案 2 :(得分:0)

export class CbButtonComponent {

     @Output() onClick: EventEmitter<string> = new EventEmitter<string>();

     onBtnClick(): void {
        this.onClick.emit('clicked');
    }
}

在您的浏览器组件中

HTML

<div>
    <h1>browser title</h1>
    <cb-button (onclick)="buttonclicked($event)"></cb-button>
</div>

组件

@Output() buttonClick: EventEmitter<string> = new EventEmitter<string>();

buttonclicked(clickedEvent){
   this.buttonClick.emit('clicked');
}

在您的父主要组件

<topology-browser [campus]="campus" (buttonClick)="buttonComponentClicked($event)"></topology-browser>

组件代码

buttonComponentClicked(buttonClicked){
       /// method calls goes her

}

通过这种方式,您将通过主要组件中再次捕获的点击通知浏览器组件并进行处理

答案 3 :(得分:0)

您可以尝试以下方法。我没试过这个,但我猜它可能有用。按钮组件发出一个由主要组件捕获的事件。

您也可以通过公共服务传递数据并将该服务注入子组件并调用服务函数来更新主要组件订阅的服务可观察对象

您的主要内容

@Component({
  template `
    <button-comp (onClick)="mainMethod($event)"></button-comp>
  `,
  directives: [ ButtonComponent ]
})
export class MainComponent {
  (...)

  mainMethod(event) {
    console.log(event)
  }
}

您的按钮组件

@Component({
    selector: 'cb-button',
    templateUrl: 'cb-button.component.html',
    styleUrls: ['cb-button.component.scss']
})

export class CbButtonComponent {

     @Output() onClick: EventEmitter<any> = new EventEmitter();

     onBtnClick(): void {
        this.onClick.emit('hello');
    }
}

button component html

<div (click)="onBtnClick()">
    <button>btn</button>
</div>