使用“ @ViewChild”中的信息时,如何避免出现“ ExpressionChangedAfterItHasBeenCheckedError”或“无法读取未定义的属性”?

时间:2019-12-12 00:16:13

标签: javascript node.js angular typescript ecmascript-6

我想了解有关@ViewChild及其工作方式的一些问题。 我使用的是角度8,由于某种原因,我遇到了一些错误,例如“ ExpressionChangedAfterItHaHasBeenCheckedError”或“无法读取未定义的属性...”

我试图在我的@ViewChild上使用{static: false},但是遇到了同样的错误。那么,如何解决这个问题及其运作方式呢?

我知道,子组件在显示父组件之后运行。我使用了诸如ngAfterViewInit和AfterViewChecked之类的方法来等待子级信息,但是我遇到了同样的错误。我想念什么吗?

以下是我的代码:

app-parent.component.ts

@Component({ selector: 'app-parent', templateUrl: './app-parent.component.html' })
export class AppParentComponent implements OnInit, AfterViewChecked {

  @ViewChild('backbtn', {static: false}) backReference : ChildBackComponent;
  previousurl : string = null;

  /*...codes...*/
  ngAfterViewChecked() {
    this.previousurl = this.backReference.previousUrl;
  }
  /*...codes...*/

app-parent.component.html

<!-- HTML codes -->
<app-child-back-button #backbtn >Button</app-child-back-button>
<app-another-child-element *ngIf="currentUrl" [url]="previousurl" ></app-another-child-element>

child-back-button.component.ts

@Component({ selector: "app-child-back-button", templateUrl: "./child-back-button.component.html" })
export class ChildBackComponent implements OnInit {
  public previousUrl: string = "/";

  ngOnInit() {
    this.previousUrl = "/previousurl";
  }

child-back-button.component.html

<a routerLink="{{ previousUrl }}"><ng-content></ng-content></a>

修改

感谢@ tony-ngo,我解决了这个问题。

只需将我的代码更改为

app-parent.component.ts

@Component({ selector: 'app-parent', templateUrl: './app-parent.component.html' })
export class AppParentComponent implements OnInit, AfterViewInit {

  @ViewChild('backbtn', {static: false}) backReference : ChildBackComponent;
  previousurl : string = null;

  /*...codes...*/
  ngAfterViewInit() {
    setTimeout(() => {
      this.previousurl = this.backReference.previousUrl;
    }, 1000);
  }

  /*...codes...*/

恕我直言,这似乎不是一件好事,但它解决了我的问题,并且效果很好。也许您需要等待所有组件变得可用,然后才能从Viewchild获取一些信息。

另一种解决方案似乎更复杂,我必须管理和检测更改,以解决仅在开发模式下发生的问题。因此,第一个解决方案对我来说很好。谢谢!

1 个答案:

答案 0 :(得分:1)

基于此article,这里有几种修复方法

旁注,因为您正试图从视图子级获取最新的更新值,所以您需要更新代码

@ViewChild('backbtn', {static: true}) backReference : ChildBackComponent;

使用setTimeout这样的东西

  ngAfterViewChecked() {
    setTimeout(() => {
        this.previousurl = this.backReference.previousUrl;
    }, 1000); // set timeout for 1 second you can change 2000 or 3000
  }

将您的逻辑移至ngOnInit

ngOnInit() {
    this.previousurl = this.backReference.previousUrl;
  }

像这样使用ChangeDection

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush
})

或者,另一方面,您需要确保让Angular进行更改。首选的方法是使用markForCheck。