Attempt to use a destroyed view: detectChanges

2019-01-22 05:23发布

I am creating a simple UI using Angular Meteor 2.

1) I have a top navbar component which has a 'logout' button.
2) On clicking 'logout' button it redirects to 'login'.
3) Then I see this error in console : EXCEPTION: Attempt to use a destroyed view: detectChanges

Exception:

EXCEPTION: Attempt to use a destroyed view: detectChanges
browser_adapter.js:77 EXCEPTION: Attempt to use a destroyed view: detectChangesBrowserDomAdapter.logError @ browser_adapter.js:77BrowserDomAdapter.logGroup @ browser_adapter.js:87ExceptionHandler.call @ exception_handler.js:57(anonymous function) @ application_ref.js:265schedulerFn @ async.js:123SafeSubscriber.__tryOrUnsub @ Subscriber.js:225SafeSubscriber.next @ Subscriber.js:174Subscriber._next @ Subscriber.js:124Subscriber.next @ Subscriber.js:88Subject._finalNext @ Subject.js:128Subject._next @ Subject.js:120Subject.next @ Subject.js:77EventEmitter.emit @ async.js:112onError @ ng_zone.js:120onHandleError @ ng_zone_impl.js:66ZoneDelegate.handleError @ angular2-polyfills.js:394Zone.runTask @ angular2-polyfills.js:323ZoneTask.invoke @ angular2-polyfills.js:490
browser_adapter.js:77 STACKTRACE:BrowserDomAdapter.logError @ browser_adapter.js:77ExceptionHandler.call @ exception_handler.js:59(anonymous function) @ application_ref.js:265schedulerFn @ async.js:123SafeSubscriber.__tryOrUnsub @ Subscriber.js:225SafeSubscriber.next @ Subscriber.js:174Subscriber._next @ Subscriber.js:124Subscriber.next @ Subscriber.js:88Subject._finalNext @ Subject.js:128Subject._next @ Subject.js:120Subject.next @ Subject.js:77EventEmitter.emit @ async.js:112onError @ ng_zone.js:120onHandleError @ ng_zone_impl.js:66ZoneDelegate.handleError @ angular2-polyfills.js:394Zone.runTask @ angular2-polyfills.js:323ZoneTask.invoke @ angular2-polyfills.js:490
browser_adapter.js:77 Error: Attempt to use a destroyed view: detectChanges
    at ViewDestroyedException.BaseException [as constructor] (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:3349:23)
    at new ViewDestroyedException (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:10626:16)
    at DebugAppView.AppView.throwDestroyedError (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:11277:72)
    at DebugAppView.AppView.detectChanges (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:11230:18)
    at DebugAppView.detectChanges (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:11321:44)
    at ViewRef_.detectChanges (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:11011:65)
    at http://localhost:3000/app/app.js?hash=323b1216814e80ed467d95bcda255eb217d7c468:2224:23
    at ZoneDelegate.invokeTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4721:174)
    at Object.onInvokeTask (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:9393:41)
    at ZoneDelegate.invokeTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4721:72)
  -------------   Elapsed: 80 ms; At: Wed Jun 15 2016 20:22:09 GMT-0700 (PDT)   -------------  
    at Object.onScheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5734:30)
    at ZoneDelegate.scheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4704:57)
    at Zone.scheduleMacroTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4652:47)
    at http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4467:37
    at setTimeout (eval at createNamedFn (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5346:24), <anonymous>:3:37)
    at new TopNavbarComponent (http://localhost:3000/app/app.js?hash=323b1216814e80ed467d95bcda255eb217d7c468:2221:9)
    at DebugAppView._View_HomeComponent0.createInternal (HomeComponent.template.js:48:34)
    at DebugAppView.AppView.create (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:11098:21)
  -------------   Elapsed: 2 ms; At: Wed Jun 15 2016 20:22:09 GMT-0700 (PDT)   -------------  
    at Object.onScheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5734:30)
    at ZoneDelegate.scheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4704:57)
    at Zone.scheduleMicroTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4649:47)
    at scheduleResolveOrReject (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4928:22)
    at resolvePromise (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4893:29)
    at http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4930:25
    at ZoneDelegate.invokeTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4721:174)
    at Object.onInvokeTask (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:9393:41)
  -------------   Elapsed: 0 ms; At: Wed Jun 15 2016 20:22:09 GMT-0700 (PDT)   -------------  
    at Object.onScheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5734:30)
    at ZoneDelegate.scheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4704:57)
    at Zone.scheduleMicroTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4649:47)
    at scheduleResolveOrReject (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4928:22)
    at ZoneAwarePromise.then (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5011:25)
    at RuntimeCompiler.resolveComponent (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:40230:14)
    at DynamicComponentLoader_.loadNextToLocation (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:10788:31)
    at RouterOutlet.activate (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:26844:26)
  -------------   Elapsed: 0 ms; At: Wed Jun 15 2016 20:22:09 GMT-0700 (PDT)   -------------  
    at Object.onScheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5734:30)
    at ZoneDelegate.scheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4704:57)
    at Zone.scheduleMicroTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4649:47)
    at scheduleResolveOrReject (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4928:22)
    at resolvePromise (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4893:29)
    at http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4877:21
    at ZoneDelegate.invoke (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4696:161)
    at Object.onInvoke (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:9402:41)
  -------------   Elapsed: 0 ms; At: Wed Jun 15 2016 20:22:09 GMT-0700 (PDT)   -------------  
    at Object.onScheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5734:30)
    at ZoneDelegate.scheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4704:57)
    at Zone.scheduleMicroTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4649:47)
    at scheduleResolveOrReject (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4928:22)
    at resolvePromise (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4893:29)
    at http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4877:21
    at ZoneDelegate.invoke (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4696:161)
    at Object.onInvoke (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:9402:41)
  -------------   Elapsed: 0 ms; At: Wed Jun 15 2016 20:22:09 GMT-0700 (PDT)   -------------  
    at Object.onScheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5734:30)
    at ZoneDelegate.scheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4704:57)
    at Zone.scheduleMicroTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4649:47)
    at scheduleResolveOrReject (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4928:22)
    at resolvePromise (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4893:29)
    at http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4930:25
    at ZoneDelegate.invokeTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4721:174)
    at Object.onInvokeTask (http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:9393:41)
  -------------   Elapsed: 1 ms; At: Wed Jun 15 2016 20:22:09 GMT-0700 (PDT)   -------------  
    at Object.onScheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5734:30)
    at ZoneDelegate.scheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4704:57)
    at Zone.scheduleMicroTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4649:47)
    at scheduleResolveOrReject (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4928:22)
    at ZoneAwarePromise.then (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5011:25)
    at http://localhost:3000/packages/modules.js?hash=560db94ec01c0b3e8f499491ffcce7a2ec6c3c5e:26895:53
    at http://localhost:3000/packages/meteor.js?hash=ae8b8affa9680bf9720bd8f7fa112f13a62f71c3:1105:22
    at ZoneDelegate.invoke (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4696:161)
  -------------   Elapsed: 0 ms; At: Wed Jun 15 2016 20:22:09 GMT-0700 (PDT)   -------------  
    at Object.onScheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:5734:30)
    at ZoneDelegate.scheduleTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4704:57)
    at Zone.scheduleMicroTask (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4649:47)
    at scheduleResolveOrReject (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4928:22)
    at resolvePromise (http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4893:29)
    at http://localhost:3000/packages/barbatus_angular2-runtime.js?hash=fda9b73362c52e988ad030102a9f58e4d584cda3:4877:21
    at http://localhost:3000/packages/meteor.js?hash=ae8b8affa9680bf9720bd8f7fa112f13a62f71c3:1105:22BrowserDomAdapter.logError @ browser_adapter.js:77ExceptionHandler.call @ exception_handler.js:60(anonymous function) @ application_ref.js:265schedulerFn @ async.js:123SafeSubscriber.__tryOrUnsub @ Subscriber.js:225SafeSubscriber.next @ Subscriber.js:174Subscriber._next @ Subscriber.js:124Subscriber.next @ Subscriber.js:88Subject._finalNext @ Subject.js:128Subject._next @ Subject.js:120Subject.next @ Subject.js:77EventEmitter.emit @ async.js:112onError @ ng_zone.js:120onHandleError @ ng_zone_impl.js:66ZoneDelegate.handleError @ angular2-polyfills.js:394Zone.runTask @ angular2-polyfills.js:323ZoneTask.invoke @ angular2-polyfills.js:490
Subscriber.js:229 Uncaught Attempt to use a destroyed view: detectChanges

top-navbar.component.ts

"use strict";
import {Logger} from "../services/logger.service";
import {Component, ChangeDetectionStrategy, ChangeDetectorRef} from '@angular/core';
import {User} from "../models/user";
import {Router} from '@angular/router-deprecated';
import {UserService} from "../services/user.service";
import {CORE_DIRECTIVES} from '@angular/common';
import {DROPDOWN_DIRECTIVES} from '../../node_modules/ng2-bootstrap';

@Component({
    selector: 'top-navbar',
    templateUrl: 'client/top-navbar/top-navbar.html',
    bindings: [UserService, Logger],
    directives: [CORE_DIRECTIVES, DROPDOWN_DIRECTIVES]
})

export class TopNavbarComponent {

    public user:User;

    public statusDropdown = {
        isOpen: false
    };

    constructor(private userService:UserService, private router:Router, private logger:Logger, private ref:ChangeDetectorRef) {
        setTimeout(() => {
            this.ref.markForCheck();
            this.user = this.userService.getLoggedInUser();
            this.ref.detectChanges();
        }, 0)
    }

    logout() {
        this.logger.warn('[Top Navbar] Logging out the user.');
        localStorage.clear();
        this.router.navigateByUrl('/login');
    }
}

and this is my login.component.ts

"use strict";
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { FormBuilder, ControlGroup, Validators } from '@angular/common';
import { MeteorComponent } from 'angular2-meteor';
import { Router } from '@angular/router-deprecated';
import { Logger } from "../services/logger.service";

@Component({
    selector: 'login',
    templateUrl: 'client/login/login.html',
    changeDetection: ChangeDetectionStrategy.OnPush,
    bindings: [Logger]
})

export class LoginComponent extends MeteorComponent {

    loginForm:ControlGroup;
    loginFailed = false;

    constructor(private _logger:Logger, private _router:Router, private ref:ChangeDetectorRef) {
        super();
        let fb = new FormBuilder();
        this.loginForm = fb.group({
            username: ["", Validators.required],
            password: ["", Validators.required]
        });
    }

    login() {


        this.call('authenticateUser', this.loginForm.value.username, this.loginForm.value.password, (err, data) => {

            if (err) {
                this._logger.error(err);

            } else {
                this._logger.info('[Authentication API] ', data);

                if (data.status != 'LOGIN_SUCCESS') {
                    this.loginFailed = true;

                } else {
                    this.loginFailed = false    ;
                    var user = {
                        id: data.id,
                        name: data.name,
                        role: data.role
                    }
                    localStorage.setItem('user', JSON.stringify(user));
                    this._router.navigate(['Home'])
                }
                //This is required for letting Angular know that something has changed.
                //Because this part of code runs out of Angular zone.
                this.ref.markForCheck();  // Mark this component and its children for change detection in next detecting cycle.
                this.ref.detectChanges(); // Trigger change detection.

            }

        });
    }
}

13条回答
\"骚年 ilove
2楼-- · 2019-01-22 06:00

Not much related to specific question, but I landed here by googling the same error so I'll share my workaround. The problem was that I was calling fixture.detectChanges() inside fixture.whenStable().then(() => {}) without wrapping the test within an async function.

Before:

it('should...', () => {
  fixture.whenStable().then(() => {
    fixture.detectChanges();
  });
});

After:

it('should...', async(() => {
  fixture.whenStable().then(() => {
    fixture.detectChanges();
  });
}));
查看更多
对你真心纯属浪费
3楼-- · 2019-01-22 06:01

Simple:

import { OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject';

export class Component implements OnDestroy {
    componentDestroyed: Subject<boolean> = new Subject();

constructor() { }

function() {
   this.service.serviceFunction
     .takeUntil(this.componentDestroyed)
     .subscribe((incomingObservable: Type) => {
       this.variable = incomingObservable;
     });
  }

ngOnDestroy() {
   this._cdRef.detach(); //If you use change dectector
   this.componentDestroyed.next(true);
   this.componentDestroyed.complete();
}
查看更多
Summer. ? 凉城
4楼-- · 2019-01-22 06:01

Simply detach ChangeDetectorRef on OnDestroy lifecycle hook and check whether the ChangeDetectorRef destroyed before executing the detectChanges method

    constructor(private cd: ChangeDetectorRef){}

    someFunction(){
      if(!this.cd['destroyed']){
        this.cd.detectChanges();
      }
    }

    ngOnDestroy(){
      this.cd.detach();
    }
查看更多
姐就是有狂的资本
5楼-- · 2019-01-22 06:04

You can use

this.cdref.markForCheck();

instead of this.cdref.detectChanges(); in many cases. But the best approach is follow @Al-Mothafar tips

查看更多
三岁会撩人
6楼-- · 2019-01-22 06:07

I solved the same issue of yours, but with much smaller code, I'll tell you the point that could help you to solve the issue.

The issue clearly comes from detectChanges() because the changes were done and the method called during the destroy phase of the component.

So you need to make your component to implements OnDestroy, then you need to cancel the changes that make this.ref.detectChanges() to be called. so your TopNavbarComponent must be similar to:

export class TopNavbarComponent implements OnDestroy {
  // ... your code

  ngOnDestroy() {
    this.cdRef.detach(); // do this

    // for me I was detect changes inside "subscribe" so was enough for me to just unsubscribe;
    // this.authObserver.unsubscribe();
  }
}

P.S: Don't forget to unsubscribe() all observers that you have in your component! Anyways you have to do that, subscriptions without unsubscribing could be the main reason for hundreds of issues including this, refer to Angular/RxJs When should I unsubscribe from `Subscription`

Edit: I know other solution around in the web trying to just solve the issue by handling the error itself, while the best practice is to know the root of the issue, check if the view destroyed or not is a good solution but the original cause could be a problem behind memory leak, so the root of the issue is that running service need to be killed NOT just try to kill the error itself without the root, for instance, running subscriptions (specially your custom one) must be closed.

SO housekeeping stuff is necessary for better performance, it is not always an easier and faster solution is the better one, if you do hide the dirt under carpets does not mean that you cleaned your room :)

查看更多
beautiful°
7楼-- · 2019-01-22 06:09

My solution was to unsubscribe all observers.

Subscription:

ngOnInit() {
     this._currentUserSubscription = this._auth.currentUser.subscribe(currentUser => {});
}

Unsubscription with changeDetector.detach():

ngOnDestroy() {
    this._currentUserSubscription.unsubscribe();
    this._cdRef.detach();
}

That was necesery on my code, i also have must use ChangeDetectorRef functionality, only those two things ishhued my code without errors.

查看更多
登录 后发表回答