如何从父组件调用路由器出口子组件方法

时间:2017-08-29 22:59:06

标签: angular typescript

我是angular2的新手

<parent>
<router outlet><router outlet>
</parent>

我在父组件中有一个按钮,如果我单击该按钮,它应该调用子组件中的方法(在路由器插座中加载。)

有没有办法从父级调用子组件(在路由器插座中)方法。

10 个答案:

答案 0 :(得分:8)

基本上有两种显示组件模板的方法:作为嵌套组件或路由目标。

嵌套组件

如果使用嵌套组件,则组件被视为具有“父组件/子组件”关系。

父组件的Html将如下所示:

<div>
   <child></child>
</div>

其中“child”是子组件的选择器。然后,您可以使用@Input和@Output属性在两者之间进行通信。

如果您有嵌套组件时有关此技术的详细信息,请查看此处的文档:https://angular.io/guide/component-interaction

路由目标

如果您通过在<router-outlet>中显示组件作为路由目标,那么就没有“父组件”和“子组件”关系。

在这种情况下,组件之间进行通信的最佳方式是使用服务。

我有一篇关于在此处创建服务的博文:https://blogs.msmvps.com/deborahk/build-a-simple-angular-service-to-share-data/

<强>资源

如果您是Angular的新手,通过完成教程或在线课程,您可以节省大量时间和挫折感。这将介绍所有基本概念,以便您快速使用Angular。

您可以在此处完成“英雄之旅”教程:https://angular.io/tutorial

或观看此类课程:https://app.pluralsight.com/library/courses/angular-2-getting-started-update

或者这一个:https://app.pluralsight.com/library/courses/angular-2-first-look/table-of-contents

(您可以注册免费的一周。)

答案 1 :(得分:8)

如果孩子在router-outlet,您可以使用ContentChild来调用孩子的方法。所以......

import { ContentChild } from '@angular/core';
在你父母的

@ContentChild(ChildComponent)
private childComponent: ChildComponent;

并点击您的点击事件:

this.childComponent.doSomething()

您还需要在parent:

中的providers数组中添加子组件
@Component({
  selector: 'parent',
  ...
  providers: [ChildComponent]
})

答案 2 :(得分:5)

我找到了两种方法来实现这一目标:

<强> 1。将主要成分注入儿童

您可以向主组件添加事件,将主要组件注入子组件并订阅事件。请参阅说明这一点的plunk。但是,现在您的孩子依赖于您的主要组件。这可能不太好。

  

主要成分

executeAction: EventEmitter<any> = new EventEmitter();
constructor() { }
performAction() {
  this.executeAction.emit();
}
  

constructor(private appComponent: AppComponent) {
    this.executeAction = this.executeAction.bind(this);
    eventSubscriber(appComponent.executeAction, this.executeAction);
}
ngOnDestroy(): void {
    eventSubscriber(this.appComponent.executeAction, this.executeAction, true);
}
executeAction() {
    alert('1');
}

<强> 2。实施服务

此处和Parent and children communicate via a service中描述的最佳解决方案是创建一个服务,该服务将成为主要组件和子组件之间的附加层。这样,您将独立于主要组件实现。请参阅说明此方法的plunk

  

服务

subscription = new Subject();
executeAction() {
    this.subscription.next();
}
  

主要成分

constructor(private appService: AppService) { }
performAction() {
  this.appService.executeAction();
}
  

constructor(private appService: AppService) {
    this.executeAction = this.executeAction.bind(this);
    eventSubscriber(appService.subscription, this.executeAction);
}
ngOnDestroy(): void {
    eventSubscriber(this.appService.subscription, this.executeAction, true);
}
executeAction() {
    alert('1');
}

答案 3 :(得分:2)

我认为Event emitter可以帮你解决问题

虽然您可以直接在子组件中使用它,但是在这里使用公共服务将是一个很好的做法

首先,您需要在服务中创建类似

的发射器
export class EmitterService {
   public nameEmitter:EventEmitter<string>=new EventEmitter(); 

    //method to get question
    changeName(name:string){   
        this.nameEmitter.emit(name)    
    }

}

然后在root组件中注入服务依赖项并调用change name方法来发出更改

 constructor(private emitter :EmitterService) {}
 this.emitter.changeName("New Name");

最后,子组件订阅了更改

this.emitter.nameEmitter.subscribe(name=>{this.name=name})

这是有效的plunker

答案 4 :(得分:2)

您可以使用shared service与路由器添加的组件进行通信。

您也可以使用路由器插座的activate event让父母知道路由器何时添加了某个组件

<强>模板

<router-outlet (activate)="onActivate($event)"></router-outlet>

<强>组件

  onActivate(componentRef){
    componentRef.works();
  }

儿童比赛

 works(){
    console.log("works");
  }

答案 5 :(得分:1)

这也可以通过以下方式实现:

.html

<parent>
    <router-outlet (activate)="onActivate($event)"><router-outlet>
</parent>

.ts

activatedComponentReference:any

onActivate(activatedComponentReference) {
  this.activatedComponentReference = activatedComponentReference;
}

onBtnClick() {
   const childRouteComp = this.activatedComponentReference as ChildRouteComponent;
   childRouteComp.childFunction();
}

答案 6 :(得分:0)

有两种方法可以从父组件调用路由器出口子组件方法。

  1. ViewChild / ViewChildren - 您可以使用ViewChild / ViewChildren从视图DOM中获取与选择器匹配的元素或指令。路由器插座呈现子组件并不重要。

    从'@ angular / core'导入{ViewChild}; @ViewChild(HomeComponent) private childComponent:HomeComponent;

  2. 然后你可以调用任何方法,

    this.childComponent.changeTitle();
    

    Demo - call router outlet child component method

    1. 共享服务 - 由于角度服务通过将它们注入您的控制器而是单例,因此您可以调用方法。 (以上答案已经提到了这种方法)

答案 7 :(得分:0)

在搜索了很多有关此问题的内容之后,我找到了解决方案,希望它可以为您提供帮助。 contentChild / ViewChild无法访问路由器出口中加载的组件(及其数据),并且使用sharedService需要一个额外的文件和更多的代码。

您只需要阅读路由器出口中加载的组件:

  1. 将模板参考添加到路由器出口:

    <router-outlet #myRouterOutlet ></router-outlet>
    
  2. 从@ angular / router导入RouterOutlet:

    import {...
       RouterOutlet,
       ..} from "@angular/router";
    
  3. 最后,使用它:

    @ViewChild("myRouterOutlet", { static: true }) routerOutlet: RouterOutlet;
    buttonClicked(){
        const childComp = this.routerOutlet.component as childComponent;
        childComp.childFunction();
    }
    

希望它可以帮助您:)

答案 8 :(得分:0)

尽管这是一个古老的问题,但这里的所有答复都不是完美的。

通过使用服务实例或子实例,您将自己绑定到特定功能 您需要呼叫的名字。服务还会强制您使用依赖项注入。

有一个更好的方法,就是使用一条指令,该指令可以使每一端完全独立 从另一个。

指令为ng-router-outlet-comm

答案 9 :(得分:0)

以上解决方案均未在Angular 10中为我工作。让我与您分享为管理此问题而创建的CustomEventHandler服务:

@Injectable()
export class CustomEventHandler {

    private eventHandlersMap: Map<string, Function> = new Map();

    constructor() {
    }

    public callEvent(eventName: string, data?: any): void {
        this.eventHandlersMap.get(eventName)(data);
    }

    public addListener(eventName: string, callback: Function): void {
        this.eventHandlersMap.set(eventName, callback);
    }
}

您可以在子组件构造函数中添加侦听器,并从父组件调用组件中的任何方法。

// add listener in child component
this.customEventHandler.addListener("some-event", this.someMethodToCall.bind(this));
// call this in parent component
this.customEventHandler.callEvent("some-event");