ViewDestroyedError: Attempt to use a destroyed view: detectChanges

Viewed 62663

I have the following component that creates an 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()
    } )
  }
}

The component below creates a button that when clicked closes the MdDialog created above by sending and event that is intercepted within the SideNavsComponent#ngOnInit method

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

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

The MdDialog is closed(), but a detection change error always occurs with the following:

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: {…}}

How can I prevent the changeDetection firing after the component is destroyed; in otherwords how can I make this code work without the error?

NB: Tried many suggestions on stackoverflow but none worked.

Thanks

3 Answers

Padegal Saigiriraj is right. But instead of ViewRef_ use ViewRef. In short:

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

ViewRef stands for Angular view, specifically the host view as Angular site describes.

the reason that this issue is happening that you are deleting the reference on the sortableData or dragableData on the change event. in abstract class, the detectChange method is waiting for 250 ms before firing the change detect, at that time your view and component will be destroyed.

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