Angular Material Dialog&热门模块重新加载

时间:2017-12-07 16:56:12

标签: angular angular-material2 webpack-hmr

到目前为止,我已成功完成以下任务:

✓HMR(热模块重新加载)设置
✓角度(5)和材料运作良好
✓打开一个对话框(下面的代码片段)

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

✓在对话框或对话框的父控制器上进行更改 ✓MMR被触发(yay)
✖对话挂起死机状态,由于对话框和背景被“卡住”而无法点击,页面基本上被冻结

我试图在父对话控制器中挂钩ngOnInitngOnDestroy以关闭对话框引用(如果存在),我也试过dialog.closeAll(),但这有没工作。此外,理想情况下,对话框不必关闭,但我似乎无法修复此僵尸对话框问题。

有没有人遇到过这个?

1 个答案:

答案 0 :(得分:4)

我一直在努力解决这个问题,并找到了一个不太理想的解决方案。它在hmr destroy事件期间从DOM中删除任何角度对话框。

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

然后在OnInit中,我们重新创建所有打开的对话框,并传入其数据。唯一的问题是此解决方案保留旧的对话框实例,因此它们不能从后台单击中解除。但是,如果对话框上有一个关闭按钮,则它会正常关闭。 StateService中的OpenDialogs属性可能会更改为完整的componentInstances的TemplateRef [],这可能会解决问题,但我不确定。

无论如何,一个黑客解决方案,直到官方支持对话+ hmr到达。

<强> 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);