【问题标题】:@ViewChild returns undefined@ViewChild 返回未定义
【发布时间】:2023-03-21 11:35:01
【问题描述】:

由于某种原因,我的 Angular 5 应用程序中的 @ViewChild 不起作用。 我在我的组件中这样定义它:

case-detail.component.html:

<div class="inner-tab-content" #innerTabContent>
    <!-- // more content here -->
</div>

我已经在我的控制器中(在构造函数上方)实现了@ViewChild,如下所示:

case-detail.component.ts

@ViewChild('innerTabContent') tabContentElement: ElementRef;

我想在组件中访问它: case-detail.component.ts

ngAfterViewInit() {
    console.log("scroll top: " + this.tabContentElement.nativeElement);
}

我已经实现了AfterViewInit 接口。 ngAfterViewInit() 被正确调用。但是,this.tabContentElement 始终是 undefined

非常感谢任何帮助:)

【问题讨论】:

  • 你能告诉我们你是如何实现@ViewChild的吗?
  • 当然,刚刚更新了我的答案:)
  • 如果您使用#innerTabContent,您将直接拥有elementRef 而不是nativeElementconsole.log(this.tabContentElement) 你会得到 HTML 元素
  • @Aravind 那也不起作用。 this.tabContentElement 不幸的是未定义。
  • @dave0688 定义 #innerTabContent 元素的块是否可能在某些 *ngIf 或其他在 afterviewinit 时未呈现的条件模板中?

标签: angular viewchild


【解决方案1】:

ViewChild() 在最新的 plunker Angular 版本和您描述的场景下运行良好。

在这个 plunker 中的演示:https://plnkr.co /edit/KzWnkE5Hvp7NUow6YAxy

编辑:这是上述 Plunker 的替换 StackBlitz:https://stackblitz.com/edit/angular-ivy-pzaglm

组件:

ngAfterViewInit() {
    console.log(this.testView); // correctly outputs the element in console, not undefined
}
  • 检查 ElementRef 和 ViewChild 是否从 '@angular/core' 正确导入

  • 您的元素可能在 AfterViewInit 时根本不存在(例如,如果有 *ngIf(根据您的 cmets 似乎是这种情况)

在后一种情况下,您可以使用包装元素和 ViewChildren ,当添加新的子元素时会发出一些事件 - 有关文档的更多信息:https://angular.io/api/core/ViewChildren

请注意,根据以下问题,本机 div 可能存在一些问题:@ViewChildren does not get updated with dynamically added DOM elements,但这可以通过使用包装您的 div 的新组件来解决,例如。

编辑

或者你也可以使用超时来等待组件被渲染。我必须说我觉得这个解决方案很“脏”,但很高兴它对你有用:)

【讨论】:

  • 依赖超时是一个非常糟糕的主意。
  • 为什么 *ngIf 会导致 AfterViewInigt 元素不出现的问题?
  • @IcedD​​ante 不确定我是否正确理解了您的实际问题,但如果*ngIf="condition" 中的条件是 falsy,那么实际元素将不会出现在 DOM 中一点也不。所以你不能选择它。这是 Angular 的预期行为。
  • 哦,好吧...是的,我想是因为您说元素“可能...当时不存在”,它稍后会由于某种原因异步出现。
  • @Orin 感谢您的通知!我创建了一个替代 StackBlitz。
【解决方案2】:

但是,即使您访问AfterViewInit 中的子组件,有时@ViewChild 仍会返回null。问题可能是由*ngIf 或其他指令引起的。

解决方案是使用@ViewChildren 代替@ViewChild 并订阅组件准备就绪时执行的changes 订阅。

例如,如果在父组件ParentComponent中你想访问子组件MyComponent

import { Component, ViewChildren, AfterViewInit, QueryList } from '@angular/core';
import { MyComponent } from './mycomponent.component';

export class ParentComponent implements AfterViewInit
{
  //other code emitted for clarity

  @ViewChildren(MyComponent) childrenComponent: QueryList<MyComponent>;

  public ngAfterViewInit(): void
  {
    this.childrenComponent.changes.subscribe((comps: QueryList<MyComponent>) =>
    {
      // Now you can access to the child component
    });
  }
}

【讨论】:

  • 但是,如果 this.childrenComponent 在您到达 ngAfterViewInit 时仍未定义,您会怎么做 :(
  • 我认为您的代码中缺少某些内容,因为this.childrenComponent 是模板组件的引用。如果您将代码放在“CodeSandbox”上,我可以尝试帮助您。
【解决方案3】:

为了让这个在我的情况下始终如一地工作,我替换了所有出现的

*ngIf="check"

[style.display]="check ? 'block' : 'none'"

否则,在我的视图首次加载时不存在的 ViewChild 组件可能会保持未定义。

【讨论】:

  • 不适用于动态添加的控件,例如单击按钮时添加的表格行
【解决方案4】:

有时,对这个问题的不同答案是,当您访问子组件时,它仍未呈现。对我来说,这是由于 *ngIf 导致子组件仍然不存在。例如,

<div *ngIf="check">
   <app-child-item></app-child-item>
</div>

在您的父 .ts 文件中,您尝试在 check 设置为 false 时访问 childItem。

【讨论】:

    猜你喜欢
    • 2017-03-11
    • 2019-10-03
    • 2018-05-14
    • 2018-10-25
    • 2019-10-19
    • 2017-01-08
    • 2019-07-28
    • 2020-03-25
    • 2016-04-29
    相关资源
    最近更新 更多