Angular 4 - @ViewChild 组件未定义

Posted

技术标签:

【中文标题】Angular 4 - @ViewChild 组件未定义【英文标题】:Angular 4 - @ViewChild component is undefined 【发布时间】:2018-01-24 08:53:25 【问题描述】:

我有一个名为 ToastComponent 的 toast 通知组件,我想从任何其他组件调用它。我是这样实现的:

ToastComponent:

export class ToastComponent implements OnInit 

  constructor() 

  showToast() 
    // some code
  

app.component.html:

<llqa-main-container>
  <llqa-header></llqa-header>
  <div class="content-container">
    <main class="content-area">
      <llqa-toast></llqa-toast> <!-- ToastComponent which I want to call -->
      <router-outlet></router-outlet>
    </main>
  </div>
</llqa-main-container>

UserManagementComponent&lt;router-outlet&gt; 内:

export class UserManagementComponent implements OnInit 

  @ViewChild(ToastComponent) toast: ToastComponent;

  constructor() 

  someSaveMethod() 
    this.toast.showToast() // throws error below
  

在调用someSaveMethod() 方法时,我会得到toast 未定义的错误。

如果我从app.component.html 中取出&lt;llqa-toast&gt;&lt;/llqa-toast&gt; 并将其放在user-management.component.html 之上,它可以正常工作,但是我必须将它放在每个组件中。我怎样才能让它工作?

【问题讨论】:

someSaveMethod 在哪里被调用?尝试使用console.log() 语句检查ToastComponent 的构造函数是否在您调用someSaveMethod 之前被调用。 【参考方案1】:

由于在您的情况下,祖父 (AppComponent) 中使用了 ToastComponent,这就是您收到此错误的原因。避免此错误的一种方法是使用在某些共享服务中定义的Subject。我在我的项目中使用这种方法来显示 toast 通知。以下是你可以做到的:


将您的&lt;llqa-toast&gt;&lt;/llqa-toast&gt; 保留在app.component.html 中。

定义一个服务以基本上发出一个事件并在您的ToastComponent 中订阅该事件。例如,

实用服务:

import  Injectable  from '@angular/core';
import  Subject  from 'rxjs';

@Injectable()
export class UtilityService 

    public OnShowToast = new Subject<boolean>();

    public showToast(): void 
        this.OnShowToast.next(true);
    

您需要在您的AppModule 提供程序中注入此服务。现在将subscribe 发送到ToastComponent 中的OnShowToast 事件。

Toast 组件:

import  UtilityService  from './path/to/the/utility.service';
export class ToastComponent implements OnInit 

  constructor(private readonly utilityService: UtilityService)  

  ngOnInit()  
     this.utilityService.OnShowToast.subscribe(value =>
        
            this.showToast();
        );
  

  private showToast() 
    // some code
  

现在,您可以从任何您想要的组件调用UtilityServiceshowToast() 方法。例如,

用户管理组件

export class UserManagementComponent implements OnInit 

  // You dont need this now
  // @ViewChild(ToastComponent) toast: ToastComponent;

  constructor(private readonly utilityService: UtilityService) 

  someSaveMethod() 
    this.utilityService.showToast();
  

【讨论】:

EventEmitter 不应该在服务中使用。 ObservableSubject 也是如此。 EventEmitter 应该用于@Output()s。 @GünterZöchbauer 不知道,因为它在我的服务中也没有任何问题。谢谢。在这里更新我的代码以使用 Subject 代替。 目前它正在工作,因为 EventEmitter 只是扩展了 Subject (AFAIR),但是 Angular 团队可以在不事先通知的情况下将其更改为仍然适用于 @Output() 但可能会破坏其他用途的自定义实现, 因为@Output() 是唯一应该使用EventEmitter 的东西。 @GünterZöchbauer 感谢您提供详细信息,+1

以上是关于Angular 4 - @ViewChild 组件未定义的主要内容,如果未能解决你的问题,请参考以下文章

Angular 中的 dom 操作(ViewChild)以及父子组件中通过 ViewChild 调用子组件的方法

带有 viewchild 和指令的 Angular 组件测试

Angular: 属性装饰器ViewChild终章

ViewChild 如何在 Angular 和 Storybook 中工作?

Angular 在项目中学习@ViewChild和ElementRef的使用

Angular 2 @ViewChild 返回未定义