【问题标题】:Angular2 : how to call main component function from a child componentAngular2:如何从子组件调用主组件功能
【发布时间】:2017-08-23 18:31:16
【问题描述】:

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

我有 3 个组件,我包含在浏览器组件中的按钮组件和包含在主组件中的浏览器组件。

单击按钮时,我需要调用主组件内的函数。

按钮组件

@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>

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

ma​​in-component.ts

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

html

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

当我点击按钮时出现以下错误

Errorself.parentView.context.editCampus 不是函数

【问题讨论】:

  • 如果你想将数据传递到几层深处,你应该使用共享服务
  • 首选方法是使用共享服务并将其注入子构造函数。与stackoverflow.com/a/42405146/3103979 重复

标签: angular typescript angular2-directives angular2-components


【解决方案1】:
  • 如果你知道根组件是什么类型,可以使用Pengyy的方法。
  • 如果您事先不知道什么类型,但您可以根据需要自定义根组件,那么共享服务是一个好方法。

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

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

https://angular.io/docs/ts/latest/api/core/index/ApplicationRef-class.html

【讨论】:

    【解决方案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)
    

    【讨论】:

    • 如果ButtonComponentMainComponent 没有在同一个文件中声明,则不需要forwardRef
    • 您使用的导入是用于测试版的 :-)
    • @echonax 哎呀,对不起,我只是从很久以前制作的一个简单的测试应用程序中复制过来的,我会为此更新,谢谢。
    • @GünterZöchbauer 我对circular dependency 有误解吗?我在阅读此问题后一直牢记这一点。github.com/angular/angular/issues/3216
    • @Pengyy 根据文档跳过 self 将使用 @SkipSelf 解决循环依赖关系,您可以使用 @Optional 进行空检查。所以它会像constructor(@Skipself() @Optional() private main:MainComponent) 更多信息:angular.io/docs/ts/latest/cookbook/…
    【解决方案3】:

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

    您还可以通过公共服务传递数据并将该服务注入子组件并调用服务函数来更新由主组件订阅的服务 observable

    你的主要组成部分

    @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>
    

    【讨论】:

      【解决方案4】:
      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
      
      }
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-30
        • 2016-05-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-07
        • 2017-07-15
        • 1970-01-01
        相关资源
        最近更新 更多