【问题标题】:Rendering dynamically component in overlay在叠加层中动态渲染组件
【发布时间】:2020-02-19 20:34:38
【问题描述】:

我正在尝试提供服务以在加载时显示微调器进度,但控制台中出现错误

这里是服务:

@Injectable({
  providedIn: 'root'
})
export class LoadingLockDataService {
  public message: string;
  public loaderType: string;
  public value: number;
  public sizeType = 'fullPage';
  private overlayRef: OverlayRef = null;

  constructor(public overlay: Overlay) {}

  public setMessage(message: string): void {
    this.message = message;
  }

  public showOverlay(component: any) {
    if (!this.overlayRef) {
      this.overlayRef = this.overlay.create();
    }
    const userProfilePortal = new ComponentPortal(component);
    this.overlayRef.attach(userProfilePortal);
  }

  public hideOverlay() {
    if (!!this.overlayRef) {
      this.overlayRef.detach();
    }
  }
}

我试图在叠加层中动态渲染的组件:

<div class="spinner-wrapper" [ngClass]="{ fullPage: loadingLockDataService.sizeType === 'fullPage' }">
  <div id="center-wrapper">
    <div class="mat-spinner-wrapper">
      <mat-progress-spinner class="spinner" strokeWidth="2" mode="indeterminate"> </mat-progress-spinner>
    </div>

    <label class="mat-body label-accent">
      {{ loadingLockDataService.message }}
    </label>
  </div>
</div>
export class LoadingLockComponent implements OnInit {
  constructor(public loadingLockDataService: LoadingLockDataService) {}

  ngOnInit() {}
}

我在哪里调用服务:

ngOnInit() {
    // setTimeout(() => {
    this.loadingLockDataService.setMessage('Chargement en cours...');
    this.loadingLockDataService.showOverlay(LoadingLockComponent);
    // }, 1);

    this.someService.subscribe(response => {
      // do something
      this.loadingLockDataService.hideOverlay();
    });
  }

我遇到以下错误: “错误:ExpressionChangedAfterItHasBeenCheckedError:表达式在检查后已更改。以前的值:'fullPage:undefined'。当前值:'fullPage:true'。看起来视图是在其父级及其子级经过脏检查后创建的。它是在变更检测钩子中创建的吗?”

而且我知道 setTimeout 在我调用服务的位置,它正在工作,但我想正确地做到这一点。我觉得是因为我渲染不好动态组件。

【问题讨论】:

    标签: angular


    【解决方案1】:

    很高兴您现在发现了这一点 - 因为这是开发人员独有的错误。即,当您将此应用程序推送到生产环境时,您会发现即使您没有进行任何更改,您也不会再收到此错误。

    这里的问题在于,当您调用时,您就是服务对象。

    这里本质上发生的事情是,您的 Angular 应用程序正在询问:

    “我的加载状态如何?”
    “加载是真的。”
    “很好,你确定吗?”
    “是的。”
    “所以我会渲染它?”
    “是的。”
    “好的,呈现的(即加载状态)与加载状态相同的状态是什么?”
    “没有。”
    “为什么?”
    “因为在你问我和我显示答案之间,答案发生了变化。”
    “所以我们没有加载?”
    “没有了,不会再有了。”

    这就是为什么当您只添加 setTimeout 时它会起作用 - 但您正确识别,这不是正确的解决方案。

    您可以正确解决此问题,方法是在本地设置加载状态,然后在 DOM 组件渲染之前或全部渲染之后尽快调用答案,或者您可以要求ChangeDetectorRef 得到警报到新的更新并进行相应的更改。

    即将您的代码更新为以下内容:

    export class LoadingLockComponent implements OnInit {
      constructor(public loadingLockDataService: LoadingLockDataService) {
    
        this.loadingLockDataService.setMessage('Chargement en cours...');
        this.loadingLockDataService.showOverlay(LoadingLockComponent);
    
        this.someService.subscribe(response => {
          // do something
          this.loadingLockDataService.hideOverlay();
        });
      }
    

    您同样可以更新您的代码,以实现代码afterViewInit

    您也可以查看ChangeDetectorRef,以了解其他方式提醒您的 Angular 应用程序发生更改,而不是正常检查。

    https://angular.io/api/core/ChangeDetectorRef

    【讨论】:

    • 我已经在 afterViewInit 中尝试过,它不起作用,我不知道我是否使用不好 ChangeDetectorRef 但在 "this.loadingLockDataService.showOverlay(LoadingLockComponent );"也不行
    • 当你把它放在我描述的构造函数中?
    • @Danny 如果您使用的是ChangeDetectorRef ,您是否将组件的changeDetection 更改为changeDetection: ChangeDetectionStrategy.OnPush?否则它在这里并没有真正做任何相关的事情
    猜你喜欢
    • 1970-01-01
    • 2019-08-18
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 2014-12-18
    • 2021-02-08
    • 2022-01-25
    • 2015-09-07
    相关资源
    最近更新 更多