typescript Angular 2 @ViewChild 不工作。无法读取未定义的属性“标题”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47559141/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 05:04:55  来源:igfitidea点击:

Angular 2 @ViewChild not working. Cannot Read Property "title" of Undefined

angulartypescriptviewchild

提问by Dheeraj Naik

I am unable to access the property of component even after importing with @ViewChild. Below is the code.

即使使用@ViewChild 导入后,我也无法访问组件的属性。下面是代码。

header.monitor.component.ts

header.monitor.component.ts

import { AdminComponent } from 'admin/admin.component';
import { Component } from '@angular/core';
import { ViewChild, AfterViewInit } from '@angular/core';

@Component({
    selector: 'monitor-header',
    templateUrl: './header.monitor.component.html',
    styleUrls: ['./header.monitor.component.css']
})

export class HeaderMonitorComponent implements AfterViewInit {

    @ViewChild(AdminComponent) private admin: AdminComponent;

    private monitorTitle: string;

    ngAfterViewInit() {
        this.monitorTitle = this.admin.title;
    }
 }

header.monitor.component.html

header.monitor.component.html

<div class="text-center header h3">{{monitorTitle}}</div>

admin.component.ts

admin.component.ts

import { Component, OnInit, ViewChild } from '@angular/core';
import { ElementRef } from '@angular/core';

@Component({
  selector: 'monitor-admin',
  templateUrl: './admin.component.html',
  styleUrls: ['./admin.component.css']
})
export class AdminComponent {

  constructor() { }

  title = 'Header';

}

ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'title' of undefined TypeError: Cannot read property 'title' of undefined

错误错误:未捕获(承诺):类型错误:无法读取未定义的属性“标题”类型错误:无法读取未定义的属性“标题”

Help me resolve this error.

帮我解决这个错误。

回答by Nicholas Pesa

You should be checking for the @ViewChildin the AfterViewCheckedinstead of the AfterViewInit. Also you can bundle your @angular/coreimports like so: import { Component, ViewChild, AfterViewInit } from '@angular/core';. Then instead of implementing AfterViewInitjust implement AfterViewChecked.

您应该检查@ViewChildinAfterViewChecked而不是AfterViewInit。你也可以捆绑你的@angular/core进口,像这样: import { Component, ViewChild, AfterViewInit } from '@angular/core';。然后,而不是实施AfterViewInit只是实施AfterViewChecked

Here is how it could look:

这是它的外观:

import { AdminComponent } from 'admin/admin.component';
import { Component, ViewChild, AfterViewChecked } from '@angular/core';

@Component({
    selector: 'monitor-header',
    templateUrl: './header.monitor.component.html',
    styleUrls: ['./header.monitor.component.css']
})

export class HeaderMonitorComponent implements AfterViewChecked {

    @ViewChild(AdminComponent) private admin: AdminComponent;

    private monitorTitle: string;

    ngAfterViewChecked() {
        this.monitorTitle = this.admin.title;
    }
 }

One question: Are these both parent components or will one of the components be a child of the other? The reason i ask is that you may want to look into a different method of passing that variable between components as this may be achieved with an @Inputor using a service to store and set the header variable. I hope this can be of some help.

一个问题:这些都是父组件还是其中一个组件是另一个组件的子组件?我问的原因是您可能想要研究在组件之间传递该变量的不同方法,因为这可以通过使用@Input或使用服务来存储和设置标头变量来实现。我希望这能有所帮助。

EDIT:

编辑:

To answer your comment, you should create a service like this:

要回答您的评论,您应该创建一个这样的服务:

import { Injectable } from '@angular/core';

@Injectable()
export class HeaderService {

  _title: string;

  constructor() { }

  set title(title) {
    this._title = title;
  }
  get title() {
    return this._title;
  }

}

Then in your component import the service and getor setthe variable:

然后在您的组件中导入服务和/getset变量:

import { AdminComponent } from 'admin/admin.component';
import { Component, ViewChild, AfterViewChecked } from '@angular/core';
import { HeaderService } from 'path/to/your/service';

@Component({
    selector: 'monitor-header',
    templateUrl: './header.monitor.component.html',
    styleUrls: ['./header.monitor.component.css']
})

export class HeaderMonitorComponent implements AfterViewChecked {

    @ViewChild(AdminComponent) private admin: AdminComponent;

    private monitorTitle: string;

    constructor(private headerService: HeaderService) {} // Import service here


    ngAfterViewChecked() {
        this.monitorTitle = this.headerService.title;
    }
 }

You just need to make sure you set the title in one of the components using this.headerService.title = 'yourTitle';

您只需要确保使用以下组件在其中一个组件中设置标题 this.headerService.title = 'yourTitle';

I am just not sure which component gets loaded first.

我只是不确定首先加载哪个组件。

You should check out Angular Services here: https://angular.io/tutorial/toh-pt4

您应该在此处查看 Angular 服务:https: //angular.io/tutorial/toh-pt4

Also check out Angular Component Interaction here: https://angular.io/guide/component-interaction

还可以在此处查看 Angular 组件交互:https: //angular.io/guide/component-interaction

EDIT #2:

编辑#2:

Here is another way to subscribe to that title in your Service:

这是在您的服务中订阅该标题的另一种方法:

So here below I have created a Subjectthat is of type string, and a method that tells it here is the next string to hold and send.

所以在下面我创建了一个Subject字符串类型,一个方法告诉它是下一个要保存和发送的字符串。

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

@Injectable()
export class HeaderService {

  public titleSubject: Subject<string> = new Subject<string>();

  constructor() { }

  setNextTitle(title) {
    this.titleSubject.next();
  }

}

Then in your HeaderMonitorComponentyou would want to subscribe to that Subjectlike so:

然后在你HeaderMonitorComponent想要订阅Subject这样的:

import { AdminComponent } from 'admin/admin.component';
import { Component, OnInit ViewChild, AfterViewChecked } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { HeaderService } from 'path/to/your/service';

@Component({
    selector: 'monitor-header',
    templateUrl: './header.monitor.component.html',
    styleUrls: ['./header.monitor.component.css']
})

export class HeaderMonitorComponent implements OnInit, AfterViewChecked {

    @ViewChild(AdminComponent) private admin: AdminComponent;

    private monitorTitle: string;
    titleObservable: Observable<string>;

    constructor(private headerService: HeaderService) {} // Import service here

    ngOnInit() {

       this.titleObservable = this.headerService.titleSubject.asObservable();
       this.titleObservable.subscribe((title) => {
          this.monitorTitle = title;
       });
    }

    ngAfterViewChecked() {
        this.monitorTitle = this.headerService.title;
    }
 }

Then in your AdminComponent, whenever the button is clicked, call this.headerService.setNextTitle(title)and the new title which you are subscribing to in the HeaderMonitorComponent will then be acknowledged and replace the current value of monitorTitle.

然后在您的 中AdminComponent,无论何时单击按钮,都会调用this.headerService.setNextTitle(title)您在 HeaderMonitorComponent 中订阅的新标题,然后将确认并替换 的当前值monitorTitle

Just another quick way to handle the data passing through.

处理传递的数据的另一种快速方法。