【问题标题】:How do I select a ContentChild of a native element in Angular 6?如何在 Angular 6 中选择原生元素的 ContentChild?
【发布时间】:2023-03-05 07:12:01
【问题描述】:

我有一个使用内容投影的组件。

<ng-content select="button">
</ng-content>

我想在我的组件中做这样的事情:

@ContentChild('button') button: ElementRef;

但是,当我检查this.button 时,undefinedngAfterViewInitngAfterContentInit 中都是ngAfterContentInit

如果我的内容子元素是原生元素而不是自定义组件,我该如何选择它?

【问题讨论】:

    标签: angular angular6 angular-directive angular-template


    【解决方案1】:

    要了解的重要一点是,您传递给@ContentChild 的选择器不是 CSS 选择器,您无法根据其ID、类或元素类型找到内容子项。您只能使用 # 运算符搜索您为其提供的标识符名称。

    所以给定一个名为 my-comp 的组件和以下用法:

    <my-comp><button #buttonName>Click me</button></my_comp>
    

    您可以通过以下方式找到它:

    @ContentChild('buttonName') button: ElementRef;
    

    编辑

    正如 OP 对 ckTag 答案的评论中所指出的那样(他领先我一分钟),这确实意味着调用代码需要知道您希望内容被标记为特定名称。

    如果您的组件确实需要了解其子内容的详细信息,更好的答案实际上是向@ContentChild 提供指令类型:

    @ContentChild(MyButtonComponent, { read: ElementRef })
    button: ElementRef;
    

    这也更好,因为您现在可以实际期望知道内容的类型;毕竟,调用代码可以将#button 粘贴在div 上。

    这确实意味着告别使用常规 HTML button 元素,但还有其他好处。例如,您可以提供一条消息来指导您的调用代码,如下所示:

    <ng-content></ng-content>
    <div *ngIf="button">Error: Please provide a MyButtonComponent</div>
    

    【讨论】:

    • @CobusKruger 实际上,调用代码不应允许除本机按钮元素之外的任何其他内容,如果您有 ,应该这样吗?
    • @Yulian 我想念你使用了select。我仍然通常将它与我自己的指令一起使用,这意味着调用代码不需要知道“使用此模板引用名称作为按钮”之类的东西。因此,从技术上讲,要求具有给定名称的模板引用变量可能是您要求的答案,但正如您所建议的那样:这是不直观的。
    【解决方案2】:

    没有一个查询装饰器可以选择没有引用的原生元素。

    @ViewChild('button')
    @ViewChildren('button')
    @ContentChild('button')
    @ContentChildren('button')
    

    它不是 CSS 选择器。

    查询装饰器在依赖图中搜索匹配类型并选择它们。匹配类型可以是模板引用、组件或指令。

    在内容中选择特定元素的推荐方法是使用指令对其进行标记。

    @Directive({...})
    export class MyButtonDirective {}
    

    现在你可以在你的父组件中查询这个了。

    @ContentChild(MyButtonDirective) button: MyButtonDirective;
    

    当您使用字符串值时,它指的是模板变量引用。这些写成#someValue,它们可以是模板引用、组件或指令。

    <button #myButton></button>
    

    您现在可以将以上内容引用为

    @ViewChild('myButton')
    

    由于视图的工作方式,我不知道这是否适用于 ContentChild#myButton 模板变量可能在父级的依赖图中不可见。

    或者,您可以注入父组件的ElementRef,然后使用本机 JavaScript 搜索您正在寻找的子组件。从 Angular 的角度来看,这是一个不好的做法,因为这个想法是将您的应用程序与 DOM 分开。

    【讨论】:

    • 我正要发布一个带有模板引用变量的答案,如果您在ngAfterContentInit 中访问它,我可以确认它适用于@ContentChild。见this stackblitz
    • @ConnorsFan 酷。这不是我通常会做的事情。如果我在模板中看到#myButton 并且我没有看到它在该模板中的任何地方使用,那么我可能会删除它。所以你应该将它们命名为#myButtonForParent
    • @ConnorsFan 很酷,它确实有效,但这意味着 AppComponent 应该知道它应该使用具有 myButton 特定模板引用的按钮。这是它不应该意识到的事情。你不觉得吗?
    • @Yulian 我创建了通用按钮指令,其中只有button 作为它们的选择器。然后,您可以查询那些和其他组件不知道它正在发生。你只需要小心没有其他人使用相同的选择器。
    猜你喜欢
    • 1970-01-01
    • 2017-01-08
    • 2017-05-26
    • 1970-01-01
    • 2019-09-02
    • 2018-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多