【问题标题】:Getting a reference to a component in the template获取对模板中组件的引用
【发布时间】:2015-11-01 13:28:54
【问题描述】:

我想从模板中定义的组件获取引用。让我们考虑一下我有以下组件:

@Component({
    selector: 'a-component'
})
@View({
    template: '<another-component #anotherComponent></another-component>',
    directives: [AnotherComponent]
})
class AComponent {

    callAnotherComponent() {
        anotherComponent.doSomething();
    }

}

显然这不起作用,我的班级中的 anotherComponent 没有定义。但是有什么简单的方法可以做到这一点吗?在我的情况下,AnotherComponent 应该是一个弹出组件,我想简单地调用类似 myPopupCmp.showMessage("message") 的东西。

我当然可以在我的模板中使用数据绑定并像这样使用它:&lt;another-component [text]="popupText" [visible]="isPopupVisible"&gt;&lt;/another-component&gt;,并使用这两个成员通过首先设置文本然后使其可见来显示它。在大多数情况下,数据绑定是有意义的,但在这里我想封装属性并避免必须处理使用它的弹出窗口的行为。

编辑:

@EricMartinez 经过一些研究,我已经更新了你的 plnkr,这里是一个 fork 的链接:plnkr。诀窍是使用 @ViewQuery 来查询组件视图中的指令和 dom 元素。我在这个问题中发现了这个:angular2 github

现在的问题是 _results 似乎是空的,即使如果我在控制台中扩展视图我可以看到我的组件,我什至可以看到它的属性,所以数据以某种方式存在但我无法访问它。有没有使用 QueryLists 的特殊方法?使用 _results 似乎不是很干净,因为 _ 表示它应该是私有的或内部的。我也尝试过先使用,但它总是带来一个空引用。

【问题讨论】:

  • 如果让两个组件处于同一级别而不是让它们成为父子组件会怎样?据我所知,组件会创建 Shadow DOM,因此它不会像您在示例中建议的那样直接访问其子级。但是,如果您将它们放在同一级别并将another-component 作为a-component 的属性传递,您将可以访问doSomething。看到这个example
  • 我相信它会起作用,但它看起来不是很干净。我想使用@Query 和@Host 直接注入它,但我似乎无法让它工作。 @Query 总是给我一个空的 QueryList。在上述情况下,我有这样的事情:constructor(@Query(AnotherComponent) query : QueryList&lt;AnotherComponent&gt;) { console.log(query); // gives an empty list }
  • 另外问题是我的组件基本上包含一个文本和一个确定按钮,单击时会发出一个事件,以便使用它的组件可以执行诸如重置表单字段或重定向之类的操作等等。因此我需要将组件放在使用它的模板中,因为事件绑定只会上升到我相信的层次结构。
  • 嘿@ArnaudBoeglin 关于您的编辑:很好的发现。我找到了这个IQueryList,在这里你可以看到它们是如何遍历查询列表的。我知道的另一件事是,在构造函数中您无法访问结果,但您可以在 onInit 中进行操作。请参阅编辑的plnkr
  • 这里是issue。感谢@JesseGood 的建议

标签: angular typescript


【解决方案1】:

请看这个Execute method on child component, 如果您知道引用的子组件的名称,则似乎与答案中的方法相同,但无需遍历查询结果。

【讨论】:

    【解决方案2】:

    所以,总结一下,我不得不使用装饰器 @ViewQuery :

    class AComponent {
    
        private _anotherComponentQuery : QueryList<AnotherComponent>;
    
        constructor(@ViewQuery('anotherComponent') query : QueryList<AnotherComponent>) {
        this._anotherComponentQuery = query;
    }
    
        onInit() {
            for(component of this._anotherComponentQuery){
                //component.instance.callMethod()
            }
        }
    
    }
    

    这里需要注意两点,ViewQuery 返回的组件在这里是一个 ComponentRef,因为在我的模板中它是一个组件。在简单的 HTML 标记的情况下,我相信它会是一个 ElementRef。另一件事是,在我的组件的构造函数中,查询是空的,因为我相信在这个阶段还没有解析模板。 QueryList 是动态的,并且会在我的视图发生变化时更新(比如我添加了满足查询的元素)。所以诀窍是要么稍后才访问查询,例如在事件处理程序中,要么在作为组件生命周期的一部分的 onInit 中进行。奇怪的是,如果我定义生命周期 onInit 并导入 onInit,代码将永远不会通过我的方法 onInit(),而且它在不导入任何东西的情况下运行良好.. 看图!

    【讨论】:

    • 谢谢!请注意,在 onInit 中我无法获取组件,我必须在 afterViewInit() 中请求它。
    【解决方案3】:

    截至https://github.com/angular/angular/commit/b0e2ebda708cf25287a211a30ef63d84cdb92a7f,您应该能够做到:

    class AComponent {
        constructor(@Query('#anotherComponent') query:QueryList<AnotherComponent>) {
    
        }
    }
    

    【讨论】:

    • 嘿@PascalPrecht,我不是 OP,但我对你的回答很感兴趣(我不知道这种查询方式)但我无法让它工作在这个plnkr。你能看看吗? (注意:在 plnkr QueryList 中不起作用,您可以指定 QueryList 或组件的名称)
    • 所以你说它应该是 #anotherComponent in a string 而不是 AnotherComponent ?
    • 无论我尝试什么 QueryList 都是空的,明天我会看一下提交的代码,以尝试了解发生了什么。但我怀疑问题出在我们试图获取引用的组件在模板中。不过它肯定可以工作..
    • @EricMartinez 我尝试使用 plnkr 并且 QueryList 的行为确实很奇怪。在我的本地版本上,我使用 QueryList 没有问题,但列表仍然为空.. 在 DirectiveAnnotation Host 和 Query 的文档中得到了很好的解释:DirectiveAnnotation,它应该与组件一起使用它们是带有视图的指令。
    • 我取得了一些进展并更新了我的原始帖子,请参阅编辑了解更多信息。
    猜你喜欢
    • 2010-11-06
    • 2019-05-07
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-25
    • 2016-07-01
    • 2016-07-04
    相关资源
    最近更新 更多