【问题标题】:How to call router outlet child component method from parent comonent如何从父组件调用路由器出口子组件方法
【发布时间】:2018-02-07 12:32:15
【问题描述】:

我是 angular2 的新手

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

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

有没有办法从父组件调用子组件(在路由器出口中)方法?

【问题讨论】:

  • 在您的示例代码中,&lt;router outlet&gt; 应该是带有破折号的&lt;router-outlet&gt;

标签: angular typescript angular2-routing


【解决方案1】:

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

嵌套组件

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

父组件的 Html 将如下所示:

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

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

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

路由目标

如果通过&lt;router-outlet&gt;显示某个组件作为路由目标,则不存在“父组件”和“子组件”关系。

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

我在这里有一篇关于创建服务的博文: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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 这很奏效...非常感谢。我的情况是在父组件中打开了一个对话框,该对话框直接更改了子组件(通过路由器插座),但服务对象没有正确反映在子组件中。不过,不确定这对资源来说有多昂贵?
    • 这里的“eventSubscriber”是什么?我在相同的“找不到名称事件订阅者”上遇到错误
    【解决方案3】:

    有了router-outlet 中的child,您可以使用ContentChild 来调用child 中的方法。所以...

    import { ContentChild } from '@angular/core';
    

    在你的父母中:

    @ContentChild(ChildComponent)
    private childComponent: ChildComponent;
    

    然后在你的点击事件上做:

    this.childComponent.doSomething()
    

    您还需要将子组件添加到父组件的 providers 数组中:

    @Component({
      selector: 'parent',
      ...
      providers: [ChildComponent]
    })
    

    【讨论】:

    • 如果我错了,请纠正我,ContentChild 是预定义的,而 Childcomponent 是用户定义的。我试过了,但我无法从 undefined 调用 methodXXx
    • Aaah,知道我忘记了一些东西:P 您需要在父级的 providers 数组中添加子级(无需在构造函数中注入它),编辑了我的答案 :) 现在应该可以工作了。而且您在评论中所做的假设是正确的。
    • 最后一个问题,。它完美地调用了子方法。但是在子方法中。我重新分配一个变量。我没有看到基于新任务的 UI 渲染。请您提出建议。
    • 嗯,这还不够信息。你能叉出我用来展示这个问题的 plunker 吗?
    • 我已经创建了,plnkr.co/edit/e7HdIv9Mqeky00nHADvJ?p=preview 第一次单击加载子项,然后将子项加载到 routeroutlet 中。现在单击更改名称按钮。我可以从 App 组件调用该方法,但是在子组件中,名称元素未在路由器插座中呈现
    【解决方案4】:

    我认为Event emitter 可以为您解决问题

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

    首先你需要在类似的服务中创建一个发射器

    export class EmitterService {
       public nameEmitter:EventEmitter<string>=new EventEmitter(); 
    
        //method to get question
        changeName(name:string){   
            this.nameEmitter.emit(name)    
        }
    
    }
    

    然后在根组件中注入服务依赖并调用更改名称方法来发出更改

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

    最后在子组件中订阅更改

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

    这里正在工作plunker

    【讨论】:

      【解决方案5】:

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

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

      模板

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

      组件

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

      儿童补偿

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

      【讨论】:

        【解决方案6】:

        从父组件调用router outlet子组件方法有两种方式。

        1. ViewChild/ViewChildren - 您可以使用 ViewChild/ViewChildren 从视图 DOM 中获取与选择器匹配的元素或指令。路由器出口渲染子组件无关紧要。

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

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

        this.childComponent.changeTitle();
        

        Demo - call router outlet child component method

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

        【讨论】:

          【解决方案7】:

          在我对这个问题进行了很多搜索之后,我找到了一个解决方案,并希望它可以帮助你。 contentChild/ViewChild 无法访问在 router-outlet 中加载的组件(及其数据),使用 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】:

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

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

            有一个更好的方法,通过使用一个指令,使每一方完全独立 来自另一个。

            指令是ng-router-outlet-comm

            【讨论】:

              【解决方案9】:

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

              .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();
              }
              

              【讨论】:

                【解决方案10】:

                上述解决方案在 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);
                    }
                }
                

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

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

                【讨论】:

                  猜你喜欢
                  • 2016-07-06
                  • 2019-04-16
                  • 2019-11-03
                  • 2021-05-02
                  • 2018-03-09
                  • 2018-06-08
                  • 2017-01-01
                  • 2020-06-27
                  相关资源
                  最近更新 更多