【问题标题】:Angular - How to get nested component reference?Angular - 如何获取嵌套组件参考?
【发布时间】:2018-07-15 16:27:48
【问题描述】:

我正在使用 Angular 5.2.2,我想知道是否可以找到后代组件(嵌套深度 2+)

例如:

  • FirstLevelComponent (在我的应用程序中声明)
  • SecondLevelComponent (第三方组件)
  • ThirdLevelComponent (第三方组件)

FirstLevelComponent 模板

<first-level-component>
   <second-level-component></second-level-component>
</first-level-component>

SecondLevelComponent 模板

<third-level-component></third-level-component>

我想在 FirstLevelComponent 中获取 ThirdLevelComponent 实例。

  • 我尝试过使用@ViewChildren 和@ContentChildren,但没有成功。两者都返回一个空的 QueryList。
  • 我无法更改 SecondLevelComponent 代码以公开 ThirdLevelComponent,因为它是第三方组件。

这个 plunker 演示了我正在尝试做的事情:https://plnkr.co/edit/9NsYmrsJMJEi0wofQReI?p=preview


编辑 (2018/02/06)

  • 一个选项可能是继承 SecondLevelComponent 来公开 ThirdLevelComponent,但我不喜欢使用继承,它会被限制在一个深度级别。

  • 经过一番检查,我最终创建了一个帮助程序来搜索后代组件。它使用 ViewContainerRef:

      import * as NgCore from '@angular/core';
    
    @NgCore.Injectable()
    export class FindDescendantsService {
        constructor() { }
        private findRecursive(container: any, type: any, results: any[]) {
            if (!container) { return; }
            if ('nodes' in container) {
                container.nodes.forEach(n => {
                    if ('componentView' in n && n.componentView) {
                        if (n.componentView.component instanceof type) {
                            results.push(n.componentView.component);
                        }
                        this.findRecursive(n.componentView, type, results);
                        return;
                    }
    
                    if ('viewContainer' in n && n.viewContainer && n.viewContainer._embeddedViews && n.viewContainer._embeddedViews.length) {
                        n.viewContainer._embeddedViews.forEach(v => this.findRecursive(v, type, results));
                        return;
                    }
                });
            }
        }
        find(vcr: NgCore.ViewContainerRef, type: any) {
            var view = vcr['_view'];
            var results = [];
            this.findRecursive(view, type, results);
            return results;
        }
    }
    

然后在 FirstLevelComponent 我可以做:

ngAfterContentInit(){    
   var thirdLevelInstances = this.findDescendantsService.find(this.viewContainerRef, ThirdLevelComponent);
}

我不太舒服,因为它使用了一些私有变量,这些变量可能会在未来的 Angular 版本中改变名称/行为,但这满足了我现在的目标。我会等待一段时间,看看是否有更好的解决方案出现,如果没有,我认为这个助手可能是答案......

【问题讨论】:

    标签: angular


    【解决方案1】:

    为此,second component 应该有一个 third component 的实例。例如

    // First Component
    @Component({
        selector: 'first-comp',
        template: `<second-comp></second-comp>`
    })
    export class FirstComponent {
        @ViewChild(SecondComponent) secondComponent: SecondComponent;
    
        doSomething() {
             this.secondComponent.thirdComponent.doStuff();
        }
    }
    
    // Second Component
    @Component({
        selector: 'second-comp',
        template: `<third-comp></third-comp>`
    })
    export class SecondComponent{
        @ViewChild(ThirdComponent) thirdComponent: ThirdComponent;
    }  
    
    // Third Component
    @Component({
        selector: 'third-comp',
        template: `<div>Hello World</div>`
    })
    export class ThirdComponent{
        doStuff() {
           // some logic here
        }
    }    
    

    但是,我不推荐这种方法。这会创建紧密耦合的组件,也更难测试。您应该始终通过@Input@Outputs 或某些服务传递您的数据。

    【讨论】:

      【解决方案2】:

      在组件之间的角度通信只有父/子。如果您不能使用二级组件,您可以按照文档中的建议使用服务来完成此操作。

      https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-23
        • 2017-12-31
        • 2021-03-05
        • 1970-01-01
        • 2019-01-15
        • 2012-05-24
        • 2016-08-04
        • 2018-04-15
        相关资源
        最近更新 更多