动态组件内部的Angular ExpressionChangedAfterItHasBeenCheckedError

问题描述 投票:0回答:2

我将为不同的语句动态地解析组件。

因此,我为其创建了一个指令和一个组件。

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[mcmsDynamicHost]'
})
export class DynamicHostDirective {

  constructor(
    public viewContainerRef: ViewContainerRef
  ) { }

}
import { AfterViewInit, Component, ComponentFactoryResolver, Input, ViewChild } from '@angular/core';
import { DynamicHostDirective } from '@mcms/ui-kit/dynamic-host/dynamic-host.directive';

@Component({
  selector: 'mcms-dynamic-host',
  templateUrl: './dynamic-host.component.html',
  styleUrls: ['./dynamic-host.component.scss']
})
export class DynamicHostComponent implements AfterViewInit {

  @ViewChild(DynamicHostDirective) dynamicHost: DynamicHostDirective;

  @Input() component;

  constructor(
    private componentFactoryResolver: ComponentFactoryResolver
  ) { }

  ngAfterViewInit(): void {
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.component);

    const viewContainerRef = this.dynamicHost.viewContainerRef;
    viewContainerRef.clear();
    const componentRef = viewContainerRef.createComponent(componentFactory);
  }

}
// component template
<ng-template mcmsDynamicHost></ng-template>

现在我正在以这种方式使用它们。

<div *ngFor="let item of dashboard">
   <mcms-dynamic-host [component]="item.card"></mcms-dynamic-host>
</div>
    this.dashboard = [
      {cols: 2, rows: 3, y: 0, x: 0, dragEnabled: true, card: WelcomeCardComponent, title: 'Welcome to Municipal CMS!'},
      {cols: 1, rows: 3, y: 0, x: 2, dragEnabled: true, card: SiteResumeCardComponent, title: 'Site Resume'},
      {cols: 2, rows: 5, y: 3, x: 0, dragEnabled: true, card: TrafficActivityCardComponent, title: 'Traffic activity'},
    ];

呈现静态组件时没有任何问题。但是,如果我尝试将某些值绑定到动态解析的组件内的模板,例如* ngFor甚至* ngIf,则全部引发错误-ExpressionChangedAfterItHasBeenCheckedError

但是当我做这个把戏时,

ngOnInit(): void {
    setTimeout(() => {
      this.data = [
        { image: 'assets/images/green-icons/page-small.svg', title: 'Pages', count: 5 },
        { image: 'assets/images/green-icons/user-small.svg', title: 'Active Users', count: 7 },
        { image: 'assets/images/green-icons/blog-small.svg', title: 'Blog Post', count: 12, pending: 3 },
        { image: 'assets/images/green-icons/comment-small.svg', title: 'Comments', count: 54, pending: 8 },
        { image: 'assets/images/green-icons/media-small.svg', title: 'Digital Assets', count: 230 },
      ];
    }, 100);
  }

没有错误。对于我来说,这有点奇怪,无论如何我们都可以使用它,但是当我尝试使用例如@ angular / material组件时,就无法进行这种技巧。

有人遇到类似问题吗?

这里是stackblitz链接-https://stackblitz.com/edit/angular-kf3pdw

angular typescript directive angular-changedetection
2个回答
1
投票

尝试将数据分配移动到ngAfterViewInit生命周期挂钩而不是ngOninit

顺便说一句,动态组件的加载通常应使用CDK Portal


0
投票

我的代码中有一个愚蠢的错误。对于Angular v9,@ ViewChild装饰器的静态标志默认值为false。这意味着在运行更改检测后解析查询结果。为了在运行更改检测之前解决查询结果,它应该为true

Stackblitz更新了正确的答案。希望这种经验对别人有帮助!干杯!

© www.soinside.com 2019 - 2024. All rights reserved.