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

Angular 如何从父组件调用路由器出口子组件方法,angular,typescript,angular2-routing,Angular,Typescript,Angular2 Routing,我是安格拉尔的新手 <parent> <router-outlet><router-outlet> </parent> 我在父组件中有一个按钮,如果我单击该按钮,它将调用子组件中的一个方法(加载到路由器出口中) 有什么方法可以从父组件调用子组件(在路由器出口中)方法吗?显示组件模板基本上有两种方法:作为嵌套组件或作为路由目标 嵌套组件 onActivate(componentRef){ componentRef.works

我是安格拉尔的新手

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

我在父组件中有一个按钮,如果我单击该按钮,它将调用子组件中的一个方法(加载到路由器出口中)


有什么方法可以从父组件调用子组件(在路由器出口中)方法吗?

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

嵌套组件

  onActivate(componentRef){
    componentRef.works();
  }
如果使用嵌套组件,则这些组件将被视为具有“父组件/子组件”关系

父组件的Html将如下所示:

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

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

当您有嵌套组件时,有关此技术的更多信息,请查看此处的文档:

路由目标

  onActivate(componentRef){
    componentRef.works();
  }
如果通过在
中显示组件来将其用作路由目标,则不存在“父组件”和“子组件”关系

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

我在这里有一篇关于创建服务的博文:

资源

如果你对Angular还不熟悉,你可以通过辅导或在线课程为自己节省大量时间和挫折。这将介绍所有的基本概念,让你在你的方式与角度快速

您可以在此处学习“英雄之旅”教程:

或者观看这样的课程:

或者这个:


(你可以免费注册一周。)

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

1。将主要成分注射到儿童体内

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

主要成分

2。实施服务

<router-outlet (activate)="onActivate($event)"></router-outlet>
此处以及中所述的最佳解决方案是创建一个服务,该服务将成为主组件和子组件之间的附加层。这样,您将独立于主组件实现。请参见说明此方法的

服务

主要成分

孩子


使用
路由器出口中的child
,您可以使用
ContentChild
来调用child中的方法。所以

import { ContentChild } from '@angular/core';
在您的家长中:

@ContentChild(ChildComponent)
private childComponent: ChildComponent;
在您的点击事件中,请执行以下操作:

this.childComponent.doSomething()
此外,您还需要在父级中的providers数组中添加子组件:

@Component({
  selector: 'parent',
  ...
  providers: [ChildComponent]
})
我想我可以帮你

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

首先,您需要在服务中创建发射器,例如

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

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

}
最后在子组件中订阅更改

this.emitter.nameEmitter.subscribe(name=>{this.name=name})
这里正在工作

您可以使用与路由器添加的组件通信

您还可以使用路由器出口的名称让父级知道路由器何时添加组件

模板

<router-outlet (activate)="onActivate($event)"></router-outlet>
儿童薪酬

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

有两种方法可以从父组件调用router outlet子组件方法

  • ViewChild/ViewChildren-可以使用ViewChild/ViewChildren从视图DOM获取与选择器匹配的元素或指令。子组件由路由器出口渲染并不重要

    从“@angular/core”导入{ViewChild}; @ViewChild(HomeComponent) 私有子组件:HomeComponent

  • 然后你可以调用任何方法

    this.childComponent.changeTitle();
    

  • 共享服务-由于angular服务是单例的,通过将它们注入控制器,您可以调用方法。(上述答案已在本方法中提及)

  • 在我搜索了很多关于这个问题的信息后,我找到了一个解决方案,希望它能对您有所帮助。 contentChild/ViewChild无法访问路由器出口中加载的组件(及其数据),使用sharedService需要额外的文件和更多代码

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

  • 将模板引用添加到路由器出口:

    <router-outlet #myRouterOutlet ></router-outlet>
    
  • 最后,使用它:

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

  • 希望能对你有所帮助:)

    虽然这是一个老问题,但这里的回答并不完美

    通过使用服务或子实例,您可以将自己绑定到特定的函数 您需要调用的名称。服务还强制您使用依赖项注入

    有一个更好的方法,使用一个指令,使每一方完全独立 从另一个


    指令是。

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

    .html


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

    在示例代码中,
    应该是带破折号的
    。如果我错了,请纠正我,ContentChild是预定义的,Childcomponent是用户定义的。我尝试过,但我无法从undefinedAaah调用methodXXx,我知道我忘记了一些东西:P您需要在父级的providers数组中添加子级(无需将其注入构造函数),编辑了我的答案:)它现在应该可以工作了。你在评论中的假设是正确的。最后一个问题,。它完美地调用了child方法,但在child方法中。我需要重新分配一个变量。我看不到基于新任务的UI呈现。你能建议一下吗?这还不够。你能用我制作的插件来展示这个问题吗?我已经创建了,plnkr.co/edit/e7HdIv9Mqeky00nHADvJ?p=预览第一次单击加载子项,然后将子项加载到routeroutlet中。现在单击更改名称按钮。我
    this.childComponent.changeTitle();
    
    <router-outlet #myRouterOutlet ></router-outlet>
    
    import {...
       RouterOutlet,
       ..} from "@angular/router";
    
    @ViewChild("myRouterOutlet", { static: true }) routerOutlet: RouterOutlet;
    buttonClicked(){
        const childComp = this.routerOutlet.component as childComponent;
        childComp.childFunction();
    }
    
    <parent>
        <router-outlet (activate)="onActivate($event)"><router-outlet>
    </parent>
    
    activatedComponentReference:any
    
    onActivate(activatedComponentReference) {
      this.activatedComponentReference = activatedComponentReference;
    }
    
    onBtnClick() {
       const childRouteComp = this.activatedComponentReference as ChildRouteComponent;
       childRouteComp.childFunction();
    }
    
    @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");