【问题标题】:Angular 4 - @ViewChild component is undefinedAngular 4 - @ViewChild 组件未定义
【发布时间】: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 之前被调用。

标签: angular typescript angular-components


【解决方案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
猜你喜欢
  • 2017-11-16
  • 2017-04-12
  • 1970-01-01
  • 2019-06-23
  • 2019-10-19
  • 2017-01-08
  • 2018-02-25
  • 2019-07-28
  • 2020-03-25
相关资源
最近更新 更多