ViewDestroyedError: попытка использования уничтоженного вида: detectChanges

У меня есть следующий компонент, который создает MdDialog

export class SideNavsComponent implements OnInit, AfterViewInit, OnDestroy {
  eventDispatcher: EventDispatcher
  authEmailDialogRef: MdDialogRef<AuthEmailDialogComponent>

  constructor(public dialog: MdDialog,) {
    this.eventDispatcher = new EventDispatcher()
  }

  signIn( event ): void {
    this.isSignedIn = event.checked
    this.openDialog()
  }

  openDialog() {
    this.authEmailDialogRef = this.dialog.open( AuthEmailDialogComponent, {
      height: '500px',
      width: '300px',
      disableClose: true
    } )
  }

  ngOnDestroy() {
  }

  ngAfterViewInit() {
  }

  ngOnInit() {
    event_dispatcher.on( 'CLOSE authEmailDialogRef', ( target: Object ) => {
      this.authEmailDialogRef.close()
    } )
  }
}

Нижеприведенный компонент создает кнопку, которая при нажатии закрывает созданный выше MdDialog путем отправки и события, которое перехватывается в методе SideNavsComponent # ngOnInit

export class AuthEmailDialogComponent implements OnInit {
eventDispatcher: EventDispatcher = new EventDispatcher()
}

cancel() {
      event_dispatcher.dispatch( 'CLOSE authEmailDialogRef', '')
  }
}

MdDialog закрыт(), но ошибка изменения обнаружения всегда происходит со следующим:

ERROR Error: ViewDestroyedError: Attempt to use a destroyed view: detectChanges
    at viewDestroyedError (core.es5.js:8636)
    at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:12781)
    at checkAndUpdateView (core.es5.js:12122)
    at callWithDebugContext (core.es5.js:13184)
    at Object.debugCheckAndUpdateView [as checkAndUpdateView] (core.es5.js:12724)
    at ViewRef_.detectChanges (core.es5.js:10196)
    at asterisk.component.ts:37
    at ZoneDelegate.webpackJsonp.1467.ZoneDelegate.invokeTask (zone.js:414)
    at Object.onInvokeTask (core.es5.js:4119)
    at ZoneDelegate.webpackJsonp.1467.ZoneDelegate.invokeTask (zone.js:413)
View_MdDialogContainer_Host_0 @ MdDialogContainer_Host.html:1
proxyClass @ compiler.es5.js:14091
DebugContext_.logError @ core.es5.js:13124
ErrorHandler.handleError @ core.es5.js:1144
next @ core.es5.js:4757
schedulerFn @ core.es5.js:3830
SafeSubscriber.__tryOrUnsub @ Subscriber.js:236
SafeSubscriber.next @ Subscriber.js:185
Subscriber._next @ Subscriber.js:125
Subscriber.next @ Subscriber.js:89
Subject.next @ Subject.js:55
EventEmitter.emit @ core.es5.js:3816
NgZone.triggerError @ core.es5.js:4188
onHandleError @ core.es5.js:4149
webpackJsonp.1467.ZoneDelegate.handleError @ zone.js:385
webpackJsonp.1467.Zone.runTask @ zone.js:184
ZoneTask.invoke @ zone.js:476
timer @ zone.js:1491
setInterval (async)
scheduleTask @ zone.js:1501
webpackJsonp.1467.ZoneDelegate.scheduleTask @ zone.js:400
onScheduleTask @ zone.js:290
webpackJsonp.1467.ZoneDelegate.scheduleTask @ zone.js:394
webpackJsonp.1467.Zone.scheduleTask @ zone.js:225
webpackJsonp.1467.Zone.scheduleMacroTask @ zone.js:248
(anonymous) @ zone.js:1527
proto.(anonymous function) @ zone.js:1402
AsteriskComponent @ asterisk.component.ts:37
createClass @ core.es5.js:10870
createDirectiveInstance @ core.es5.js:10701
createViewNodes @ core.es5.js:12064
callViewAction @ core.es5.js:12508
execComponentViewsAction @ core.es5.js:12417
createViewNodes @ core.es5.js:12091
createRootView @ core.es5.js:11969
callWithDebugContext @ core.es5.js:13184
debugCreateRootView @ core.es5.js:12644
ComponentFactory_.create @ core.es5.js:9890
ComponentFactoryBoundToModule.create @ core.es5.js:3427
ViewContainerRef_.createComponent @ core.es5.js:10092
PortalHostDirective.attachComponentPortal @ material.es5.js:2135
MdDialogContainer.attachComponentPortal @ material.es5.js:19218
MdDialog._attachDialogContent @ material.es5.js:19486
MdDialog.open @ material.es5.js:19400
webpackJsonp.751.SideNavsComponent.openDialog @ side-navs.component.ts:39
webpackJsonp.751.SideNavsComponent.signIn @ side-navs.component.ts:35
(anonymous) @ SideNavsComponent.html:32
handleEvent @ core.es5.js:11892
callWithDebugContext @ core.es5.js:13184
debugHandleEvent @ core.es5.js:12772
dispatchEvent @ core.es5.js:8792
(anonymous) @ core.es5.js:10720
schedulerFn @ core.es5.js:3842
SafeSubscriber.__tryOrUnsub @ Subscriber.js:236
SafeSubscriber.next @ Subscriber.js:185
Subscriber._next @ Subscriber.js:125
Subscriber.next @ Subscriber.js:89
Subject.next @ Subject.js:55
EventEmitter.emit @ core.es5.js:3816
ToggleButton.toggle @ togglebutton.js:42
(anonymous) @ ToggleButton.html:4
handleEvent @ core.es5.js:11892
callWithDebugContext @ core.es5.js:13184
debugHandleEvent @ core.es5.js:12772
dispatchEvent @ core.es5.js:8792
(anonymous) @ core.es5.js:9384
(anonymous) @ platform-browser.es5.js:2683
webpackJsonp.1467.ZoneDelegate.invokeTask @ zone.js:414
onInvokeTask @ core.es5.js:4119
webpackJsonp.1467.ZoneDelegate.invokeTask @ zone.js:413
webpackJsonp.1467.Zone.runTask @ zone.js:181
ZoneTask.invoke @ zone.js:476
MdDialogContainer_Host.html:1 ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 0, nodeDef: {…}, elDef: {…}, elView: {…}}

Как я могу предотвратить срабатывание changeDetection после уничтожения компонента; в других словах, как я могу заставить этот код работать без ошибки?

NB: Пробовал много предложений о stackoverflow, но никто не работал.

Спасибо

Ответ 1

Проблема заключается в том, что диалоговое окно закрывает действие, удаляя элемент из представления, и ваш EventDispatcher НЕ ЯВЛЯЕТСЯ МЕТОДОМ УГЛОВОГО ПОЛОЖЕНИЯ, поэтому он запускается вне контекста зоны и выводит его из себя. Это выглядит так:

  • Диалог существует в поле зрения, устанавливает состояние
  • Клики закрываются
  • Запускает ваше событие, чтобы начать
  • Ваше событие прочитано (вне контекста)
  • Удаляет из вида (все еще вне контекста)
  • Обнаружение изменений, наконец, догоняет изменения в вашем компоненте, ОН СНЕП, ГДЕ КОМПОНЕНТ?

Вы можете использовать другой метод для взаимодействия с диалоговым окном или переключиться на onPush() для обнаружения изменений

Я предлагаю вам использовать ручку afterClosed:

this. authEmailDialogRef.afterClosed().subscribe(result => {
  console.log('Dialog result: ${result}'); // Pizza!
});

Я вытащил этот фрагмент прямо из документов: ЗДЕСЬ

Ответ 2

Причиной возникновения этой проблемы является то, что вы удаляете ссылку на sortableData или dragableData в событии изменения. в абстрактном классе метод detectChange ожидает 250 мс, прежде чем активировать обнаружение изменений, в это время ваш вид и компонент будут уничтожены.

setTimeout(() => {
        if (this.cdr !== null && this.cdr !== undefined &&
          !(this.cdr as ViewRef_).destroyed) {
          this.cdr.detectChanges();
        }
      }, 250);

Ответ 3

Падегал Сайгирирадж прав. Но вместо ViewRef_ используйте ViewRef. Короче говоря:

setTimeout(() => {
  if (this.cdr && !(this.cdr as ViewRef).destroyed) {
    this.cdr.detectChanges();
  }
});

ViewRef расшифровывается как Angular, в частности, представление хоста, как описывает Angular site.