Versuch, eine zerstörte Ansicht zu verwenden: detectChanges

79

Ich erstelle eine einfache Benutzeroberfläche mit Angular Meteor 2.

1) Ich habe eine obere Navigationsleisten-Komponente mit einer Schaltfläche zum Abmelden.
2) Wenn Sie auf die Schaltfläche "Abmelden" klicken, wird zu "Anmelden" weitergeleitet.
3) Dann sehe ich diesen Fehler in der Konsole:EXCEPTION: Attempt to use a destroyed view: detectChanges

Ausnahme:

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');
    }
}

und das ist meine 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.

            }

        });
    }
}
Abhishek
quelle
kommentieren Sie den Aufruf für detectChanges (); Funktion und überprüfen Sie, wo es einen anderen Fehler erzeugt
Mayur
Ich habe das gleiche Problem mit dem gleichen Szenario.
Al-Mothafar

Antworten:

96

Die einzige Lösung, die für mich funktioniert hat, war:

if (!this.changeDetectionRef['destroyed']) {
    this.changeDetectionRef.detectChanges();
}
tomaszbak
quelle
1
Gleich hier, danke! Obwohl ich mich dafür entschieden habe, isDestroyedin jeder Komponente ein privates Feld hinzuzufügen, in dem es benötigt wurde (dh in dem das Abbestellen nicht ausreichte). Ich habe das Feld in ngOnDestroy auf true gesetzt und es verwendet, anstatt zu versuchen, auf das interne Feld der Änderungsdetektorreferenz zuzugreifen.
Dbandstra
2
Diese Antwort verhindert zwar, dass der Fehler Ihre App in die Luft jagt, deckt jedoch die Grundursache ab. Al-Mothafar hat hier die richtige Lösung, nämlich detachdie cdrvon der Komponente, die nicht mehr gerendert wird.
Matt Westlake
5
Das funktioniert tatsächlich! Auf der anderen Seite scheint dies SEHR hackig zu sein, da destroyedes nicht Teil der öffentlichen API des changeDetectionRefObjekts ist. Gibt es eine Möglichkeit, dies anzuwenden, ohne es durchzusetzen ['destroyed']?
Lealceldeiro
2
Einverstanden mit @lealceldeiro. Mit den neueren Versionen von TypeScript können wir dies nicht mehr tun.
Krillgar
1
Sie können mit !(this.changeDetectionRef as ViewRef).destroyedweniger hacky ein wenig machen , aber es ist ziemlich immer noch in diesen Tagen Hacky
electrovir
85

Ich habe das gleiche Problem von Ihnen gelöst, aber mit viel kleinerem Code werde ich Ihnen den Punkt erläutern, der Ihnen bei der Lösung des Problems helfen könnte.

Das Problem ist eindeutig darauf zurückzuführen, detectChanges()dass die Änderungen vorgenommen und die Methode während der Zerstörungsphase der Komponente aufgerufen wurden.

Sie müssen also Ihre Komponente erstellen implements OnDestroy, um this.ref.detectChanges()die aufgerufenen Änderungen abzubrechen . Sie TopNavbarComponentmüssen also ähnlich sein wie:

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();
  }
}

PS: Vergessen Sie nicht unsubscribe()alle Beobachter, die Sie in Ihrer Komponente haben! Wie auch immer Sie dies tun müssen, Abonnements ohne Abmeldung können der Hauptgrund für Hunderte von Problemen sein, einschließlich Angular / RxJs. Wann sollte ich mich von "Abonnement" abmelden?

Bearbeiten : Ich kenne eine andere Lösung im Web, die versucht, das Problem nur durch Behandeln des Fehlers selbst zu lösen. Die beste Vorgehensweise besteht darin, die Ursache des Problems zu kennen und zu überprüfen, ob die zerstörte Ansicht eine gute Lösung ist, aber die ursprüngliche Ursache Dies könnte ein Problem hinter dem Speicherverlust sein. Daher liegt der Grund für das Problem darin, dass der laufende Dienst beendet werden muss. Versuchen Sie NICHT, den Fehler selbst ohne den Stamm zu beenden. Beispielsweise müssen laufende Abonnements (insbesondere Ihre benutzerdefinierten) geschlossen werden.

SO Housekeeping-Sachen sind für eine bessere Leistung notwendig, es ist nicht immer eine einfachere und schnellere Lösung ist die bessere, wenn Sie den Schmutz unter Teppichen verstecken, heißt das nicht, dass Sie Ihr Zimmer gereinigt haben :)

Al-Mothafar
quelle
Als ich das tat, bekam ich diesen Fehler bei der ngOnDestory-Funktion: console.js: 26 FEHLER Fehler: Nicht erfasst (im Versprechen): TypeError: Die Eigenschaft 'trennen' von undefiniert kann nicht gelesen werden. Typfehler: Die Eigenschaft 'trennen' von undefiniert kann nicht gelesen werden
Jun711
Dies bedeutet, dass Ihr ChangeDetectorRefServicename möglicherweise falsch ist. Wenn Sie private cdRef: ChangeDetectorRefim Konstruktor haben, sollte es funktionieren.
Al-Mothafar
1
Warum sollte die Methode ( detectChanges) während der Zerstörungsphase aufgerufen werden?
DongBin Kim
1
@DongBinKim Wenn Sie diese Option aktiviert haben detectChangesund während der Zerstörungsphase Änderungen vorgenommen wurden, werden Änderungen an der toten Komponente vorgenommen, bevor die Dienste ebenfalls ausfallen. Das Problem tritt also auf. Dies hängt mit dem View-Lebenszyklus für Winkel zusammen, wie auch immer Sie können Siehe diesen Link angle.io/api/core/ChangeDetectorRef#detectChanges und angular.io/guide/lifecycle-hooks, da Sie sehen können, dass DOM-Aufenthalte und der Dienst im Speicher versuchen, Änderungen anzuwenden, während die Komponente selbst getötet wurde.
Al-Mothafar
1
Diese Lösung hat bei mir nicht funktioniert. Tatsächlich scheint der Codekommentar für die DetectChanges-Methode darauf hinzudeuten, dass DetectChanges den Änderungsdetektor wieder anbringt. Für mich war die einzige funktionierende Lösung die Methode von tomaszbak oder immer / clearTimeout / etc.
Dbandstra
13

Sie können verwenden

this.cdref.markForCheck();

statt this.cdref.detectChanges(); in vielen Fällen. Am besten folgen Sie jedoch den Tipps von @ Al-Mothafar

Thompson
quelle
7

Ich habe es gelöst mit:

if (!(<ViewRef>this.cd).destroyed) {
   this.cd.detectChanges();
}
Vytautas Pranskunas
quelle
Fast das gleiche wie die akzeptierte Antwort, bietet aber die jetzt notwendige Typkonvertierung
Electrovir
6

Trennen Sie einfach ChangeDetectorRef vom OnDestroy-Lifecycle-Hook und prüfen Sie, ob ChangeDetectorRef zerstört wurde, bevor Sie die detectChanges-Methode ausführen

    constructor(private cd: ChangeDetectorRef){}

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

    ngOnDestroy(){
      this.cd.detach();
    }
Thilina Piyadasun
quelle
ist this.cd.detach () bei destroy notwendig?
KingMario
Wenn die Komponente nicht mehr gerendert wird, kann ChangeDetectorRef getrennt werden. Es ist nicht erforderlich, aber dabei stellen wir sicher, dass in der zerstörten Ansicht keine Änderungserkennung stattfindet. Wenn Sie jedoch wirklich sicher sind, dass keine Änderungserkennung erforderlich ist oder die Änderungserkennung in der Komponente deaktiviert werden muss, können Sie den Änderungsdetektor jederzeit abnehmen.
Thilina Piyadasun
Danke Thilina. Ich denke this.cdwird beim Zerstören automatisch losgelöst. Und wenn nicht, da !this.cd['destroyed']vor dem getestet wird , this.cd.detectChanges()in someFunction, werden Sie sicher sein , rufen someFunctionauf jeden Umstand.
KingMario
5

Sie müssen den Wert des Abonnenten in einer Variablen abrufen und sich von derselben Variablen abmelden. Bitte beziehen Sie sich auf den gleichen Code

import { Component, OnInit, ChangeDetectionStrategy, ChangeDetectorRef, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { Cartservice } from './../cartservice.service';
import { ISubscription } from 'rxjs/Subscription';



export class CartComponent implements OnInit, OnDestroy {

private subscription: ISubscription;
ngOnInit() {
    this.subscription = this.cartservice.productsObservable.subscribe(cart => {
      this.cartProducts = cart.products;
      this.cartTotal = cart.cartTotal;
      this.changeDetectorRef.detectChanges();
    });
  }

 ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

Beachten Sie, dass ich Änderungen in der Methode ngOnDestroy () abbestellt habe.

Alok G.
quelle
4

Meine Lösung bestand darin, alle Beobachter abzumelden.

Abonnement:

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

Abbestellen mit changeDetector.detach ():

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

Das war für meinen Code notwendig, ich muss auch die ChangeDetectorRef-Funktionalität verwenden, nur diese beiden Dinge haben meinen Code fehlerfrei verändert.

Dejan Kropec
quelle
2

In meinem Fall handelte es sich um ein Missmanagement des asynchronen Testaufbaus der Komponentenkonfiguration und -kompilierung.

  1. Der fehlerhafte Code hatte vor Type ( Async / Await ) eine singuläre Asynchronisierung vor jeder ()
  2. Damit es funktioniert, verwende ich zwei beforeEach (), wobei das erste Async mit Angulars async () behandelt und das zweite beforeEach () synchronisiert .

Code verursacht Fehler ..

beforeEach(async () => {
    await TestBed.configureTestingModule({
        imports: [
            BrowserAnimationsModule
        ],
        providers: [
            { provide: ComponentFixtureAutoDetect, useValue: true },
            { provide: OptionsService, useValue: optionServiceMock },
        ],
        declarations: [EventLogFilterComponent],
        schemas: [NO_ERRORS_SCHEMA]
    }).compileComponents();
    fixture = TestBed.createComponent(EventLogFilterComponent);
    component = fixture.componentInstance;
    optionsService = TestBed.get(OptionsService);
    component.filterElem = jasmine.createSpyObj('filterElem', ['close']);
    fixture.detectChanges();
});

Wurde behoben mit ...

beforeEach(async(() => {
    TestBed.configureTestingModule({
        imports: [
            BrowserAnimationsModule
        ],
        providers: [
            { provide: ComponentFixtureAutoDetect, useValue: true },
            { provide: OptionsService, useValue: optionServiceMock },
        ],
        declarations: [EventLogFilterComponent],
        schemas: [NO_ERRORS_SCHEMA]
    }).compileComponents();
}));

beforeEach(() => {
    fixture = TestBed.createComponent(EventLogFilterComponent);
    component = fixture.componentInstance;
    optionsService = TestBed.get(OptionsService);
    component.filterElem = jasmine.createSpyObj('filterElem', ['close']);
    fixture.detectChanges();
});
daniel.caspers
quelle
2

Nicht viel mit einer bestimmten Frage zu tun, aber ich bin hier gelandet, indem ich denselben Fehler gegoogelt habe, damit ich meine Problemumgehung teilen kann. Das Problem war, dass ich fixture.detectChanges()innen anrief, fixture.whenStable().then(() => {})ohne den Test in eine asyncFunktion einzuschließen.

Vor:

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

Nach:

it('should...', async(() => {
  fixture.whenStable().then(() => {
    fixture.detectChanges();
  });
}));
Carlos Roso
quelle
1

Einfach:

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();
}
Cameron Gilbert
quelle
1

Meine Ursache ist aufgetreten, als ich versucht habe, einen modalen Dialog mit NgbActiveModal zu öffnen. Anscheinend verursacht das Rufen von sich .dismiss()aus ngOnInit()dies.

export class MyModal {
    constructor(private modalInstance: NgbActiveModal) {
    }

    ngOnInit() {
       if (foo) this.modalInstance.dismiss();
    }

Die Lösung bestand darin, vor der Entlassung einen Tick abzuwarten.

if (foo) setTimeout(() => this.modalInstance.dismiss());

Ron Newcomb
quelle
1

Nun, diese Antworten haben mir nicht geholfen. Ich habe eine andere Lösung gefunden.

Die untergeordnete Komponente hat eine Ausgabe, die ausgelöst wird, wenn auf die Schaltfläche Schließen geklickt wird

<child-component
    *ngIf="childComponentIsShown"
    (formCloseEmitter)="hideChildComponent()"
></child-component>

Die Methode "hideChildComponent ()" in der übergeordneten Komponente erkennt Änderungen.

hideChildComponent() {
  this.childComponentIsShown = false;
  this.cdr.detectChanges();
}

Hoffe das wird jemandem helfen.

Levan Lomia
quelle
1

Für mich hat nur folgende Lösung funktioniert:

ngOnInit() {
    if (this.destroyedComponent) this.changeDetector.reattach();

this.destroyedComponent = false;
this.subscription = this.reactive.channel$.subscribe(msg => {
  switch (msg) {
    case "config:new_data":
      if (!this.destroyedComponent) {
        this.table.initTable();
        this.changeDetector.detectChanges();
      }
  }
})
}

ngOnDestroy() {
   this.subscription = null;
   this.destroyedComponent = true;
   this.changeDetector.detach();
}

Erläuterung:

  1. Wenn die Komponente zuvor zerstört wurde, bringen Sie den Detektor wieder an.
  2. Setzen Sie das vorherige Flag auf einen falschen Wert.
  3. Speichern Sie das RxJs-Abonnement und legen Sie die gewünschte Logik fest.
  4. Schließen Sie diese Logik in eine Bedingung ein, die prüft, ob die Komponente durch das zuvor deklarierte Flag als zerstört festgelegt wurde oder nicht.
  5. Führen Sie die gewünschte Erkennung von Änderungen in diesem Block durch.
  6. Setzen Sie die ngOnDestroy () -Methode und machen Sie das Abonnement ungültig, setzen Sie das destroyComponent-Flag auf einen true-Wert und trennen Sie den changeDetector.
Zerok
quelle
1

Um diesen Fehler zu vermeiden, versuchen Sie, anstatt modelChanges () aufzurufen, den Modelländerungscode wie folgt zu umbrechen:

this.ngZone.run(() => {
      ...
});
Martin Cremer
quelle