Angular材料对话框和热模块重载

9

到目前为止,我已经成功完成了以下工作:

✓ HMR(热模块重载)设置
✓ Angular(5)和Material运行良好
✓ 打开对话框(下面是代码片段)

// ...
constructor(private dialog: MatDialog){}
//...
public openDialog(){
    this.dialogRef = this.dialog.open(someDialogComponent, {
      width: '300px'
    });
}

✓ 在对话框或对话框的父控制器上进行更改
✓ 触发 HMR (耶)
✖ 对话框处于死亡状态,页面基本上被冻结,因为对话框和背景被“卡住”且无法点击。

我已经尝试在父控制器或对话框控制器中挂钩ngOnInitngOnDestroy,以关闭对话框引用(如果存在),我还尝试了dialog.closeAll(),但这并没有起作用。理想情况下,对话框不必关闭,但我似乎无法解决这个僵尸对话框问题。

有人遇到过这种问题吗?


3
今天我在我的项目中实现HMR时遇到了完全相同的问题。 这很奇怪。 当没有对话框打开时更新样式可以无缝进行,但一旦有对话框打开,任何需要重新编译的文件保存(更改组件样式、HTML或TS)都会导致Material对话框失去其与Material对话框样式的绑定,这实际上会导致它卡在屏幕上。 - Asaf Agranat
3
发现了这个已报告的问题,讨论了它。 - Asaf Agranat
1个回答

5

我一直在苦苦挣扎,并找到了一个不太理想的解决方案,目前只能勉强使用。它会在热模块替换销毁事件期间,将任何Angular对话框从DOM中移除。

const elements = document.getElementsByClassName('cdk-overlay-container');
for (let i = 0; i < elements.length; i++) {
  elements[i].innerHTML = '';
}

在OnInit中,我们重新创建了所有已打开的对话框,并传入它们的数据。唯一的问题是此解决方案会保留旧的对话框实例,因此无法通过后台单击将其取消。但是,如果对话框上有一个关闭按钮,则它将正确地关闭。
StateService中的OpenDialogs属性可能可以更改为包含组件实例的TemplateRef[],这可能会解决问题,但我不确定。
在正式支持对话框和HMR之前,这是一个 hack 的解决方案。
app.module.ts
export class AppModule {
  constructor(private state: StateService, public dialog: MatDialog) { }

  OnInit(store) {
    if (store !== undefined) {
      this.state.SetState(store.State);

      for (let i = 0; i < this.state.OpenDialogs.length; i++) {
        const t = this.state.OpenDialogs[i].componentInstance;
        this.dialog.open(t.constructor, { data: t.data });
      }
    }
  }

  OnDestroy(store) {
    this.state.OpenDialogs = this.dialog.openDialogs;
    store.State = this.state;

    const elements = document.getElementsByClassName('cdk-overlay-container');
    for (let i = 0; i < elements.length; i++) {
      elements[i].innerHTML = '';
    }
  }
}

state.service.ts:

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

@Injectable({
  providedIn: 'root'
})
export class StateService {

  public OpenDialogs: MatDialogRef<any>[];

  constructor() {
  }

  public SetState(_state: StateService) {
    this.OpenDialogs = _state.OpenDialogs;
  }
}

main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';


if (environment.production) {
  enableProdMode();
}

// tslint:disable-next-line:no-shadowed-variable
function bootstrap(AppModule) {
  return platformBrowserDynamic().bootstrapModule(AppModule)
    .then(moduleRef => {
      if (environment.hmr) {
        if (module['hot']) {
          module['hot']['accept']();
          if (moduleRef.instance['OnInit']) {
            if (module['hot']['data']) {
              moduleRef.instance['OnInit'](module['hot']['data']);
            }
          }
          if (moduleRef.instance['OnStatus']) {
            module['hot']['apply']((status) => {
              moduleRef.instance['OnStatus'](status);
            });
          }
          if (moduleRef.instance['OnCheck']) {
            module['hot']['check']((err, outdatedModules) => {
              moduleRef.instance['OnCheck'](err, outdatedModules);
            });
          }
          if (moduleRef.instance['OnDecline']) {
            module['hot']['decline']((dependencies) => {
              moduleRef.instance['OnDecline'](dependencies);
            });
          }

          module['hot']['dispose'](store => {
            if (moduleRef.instance['OnDestroy']) {
              moduleRef.instance['OnDestroy'](store);
            }
            moduleRef.destroy();
            if (moduleRef.instance['AfterDestroy']) {
              moduleRef.instance['AfterDestroy'](store);
            }
          });
        }
      }

      return moduleRef;
    });
}

bootstrap(AppModule);

有人找到更新了吗,还是我们仍然需要一个解决方法? - Tim Harker
1
相同的解决方法也适用于Primeng对话框。 @TimHarker 相关的Github问题已被机器人关闭。显然,十几个人不足以构成一个大型群体。https://github.com/angular/angular-cli/issues/9600 - alehro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接