Angular - 如何获得嵌套组件引用?

时间:2018-02-05 18:17: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);
}

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

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

为了做到这一点,var dragHappened; (function(H) { var addEvent = H.addEvent; H.Pointer.prototype.setDOMEvents = function() { var pointer = this, container = pointer.chart.container, ownerDoc = container.ownerDocument; container.onmousedown = function(e) { dragHappened = false; pointer.onContainerMouseDown(e); }; container.onmousemove = function(e) { pointer.onContainerMouseMove(e); }; container.onclick = function(e) { if (!dragHappened) { pointer.onContainerClick(e); } }; (...) }; // setDOMEvents })(Highcharts); (...) plotOptions: { series: { point: { events: { drag: function() { console.log('drag'); dragHappened = true; }, click: function() { console.log('click'); } } } } }, 应该有一个second component的实例。 E.g。

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或某些服务传递您的数据。