파괴 된 뷰 사용 시도 : detectChanges


79

Angular Meteor 2를 사용하여 간단한 UI를 만들고 있습니다.

1) '로그 아웃'버튼이있는 상단 navbar 구성 요소가 있습니다.
2) '로그 아웃'버튼을 클릭하면 '로그인'으로 이동합니다.
3) 그런 다음 콘솔 에이 오류가 표시됩니다.EXCEPTION: Attempt to use a destroyed view: detectChanges

예외:

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

그리고 이것은 내 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.

            }

        });
    }
}

detectChanges ();에 대한 호출을 주석 처리하십시오. 함수를 사용하고 다른 오류를 생성하는 위치를 확인합니다.
mayur

동일한 시나리오에서 동일한 문제가 있습니다.
Al-Mothafar 2017

답변:


97

나를 위해 일한 유일한 해결책은 다음과 같습니다.

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

1
여기도 마찬가지입니다. 감사합니다! isDestroyed필요한 경우 (즉, 구독 취소로 충분하지 않은) 각 구성 요소에 개인 필드를 추가하기로 결정했지만 . ngOnDestroy에서 필드를 true로 설정하고 변경 감지기 참조의 내부 필드에 액세스하는 대신 사용했습니다.
dbandstra

2
이 답변은 오류로 인해 앱이 폭파되는 것을 방지하지만 근본 원인을 다루고 있습니다. 알 - Mothafar는에 여기에 적합한 솔루션이 더 이상 렌더링되지 않는 구성 요소에서합니다. detachcdr
Matt Westlake

5
이것은 실제로 작동합니다! 다른 한편으로 이것은 객체 destroyed의 공개 API의 일부가 아니기 때문에 매우 해 키로 보입니다 changeDetectionRef. 그것을 통해 액세스하지 않고 이것을 적용하는 방법이 ['destroyed']있습니까?
lealceldeiro

2
@lealceldeiro와 동의했습니다. 최신 버전의 TypeScript에서는 더 이상이 작업을 수행 할 수 없습니다.
krillgar

1
당신은 !(this.changeDetectionRef as ViewRef).destroyed그것을 조금 덜 해 키로 만드는 데 사용할 수 있지만 요즘에는 여전히 꽤 해키입니다
electrovir

86

나는 당신과 같은 문제를 해결했지만 훨씬 더 작은 코드로 문제를 해결하는 데 도움이 될 수있는 요점을 알려 드리겠습니다.

이 문제 detectChanges()는 변경 사항이 수행되고 구성 요소의 폐기 단계에서 메서드가 호출 되었기 때문에 분명히 발생합니다.

따라서 구성 요소를으로 implements OnDestroy만들고 this.ref.detectChanges()호출 할 변경 사항을 취소해야합니다 . 따라서 다음 TopNavbarComponent과 유사해야합니다.

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

추신 : unsubscribe()컴포넌트에있는 모든 옵저버를 잊지 마세요 ! 어쨌든 당신은 그렇게해야합니다. 구독을 취소하지 않은 구독은 이것을 포함하여 수백 가지 문제의 주된 이유가 될 수 있습니다 .Angular / RxJ를 참조하십시오. 언제 구독을 취소해야합니까?

편집 : 나는 오류 자체를 처리하여 문제를 해결하려는 웹 주변의 다른 해결책을 알고 있으며, 가장 좋은 방법은 문제의 원인을 알고 뷰가 손상되었는지 여부를 확인하는 것입니다. 메모리 누수 뒤에 문제가 될 수 있으므로 문제의 근원은 실행중인 서비스를 종료해야한다는 것입니다. 예를 들어 실행중인 구독 (특히 사용자 지정 구독)을 닫아야합니다.

따라서 더 나은 성능을 위해 청소 도구가 필요합니다. 항상 더 쉽고 빠른 솔루션이 더 좋은 것은 아닙니다. 카펫 아래에 먼지를 숨기면 방을 청소한다는 의미는 아닙니다. :)


그렇게했을 때 ngOnDestory 함수에서이 오류가 발생했습니다. console.js : 26 오류 오류 : Uncaught (약속) : TypeError : 정의되지 않은 'detach'속성을 읽을 수 없습니다
.TypeError :

이것은 귀하의 ChangeDetectorRef서비스 이름이 잘못 되었음을 의미 합니까? 당신이 경우 private cdRef: ChangeDetectorRef생성자에서 작동해야합니다.
Al-Mothafar

1
detectChanges삭제 단계 에서 method ( )가 호출되는 이유는 무엇 입니까?
김동빈

1
@DongBinKim 켜고 detectChanges파괴 단계에서 변경 사항이 발생하면이 기능은 서비스가 죽기 전에 죽은 구성 요소에 변경 사항을 적용하기 시작하므로 문제가 발생합니다. 어쨌든 각도에 대한 수명주기보기와 관련이 있습니다. 이 링크를 참조하십시오 angular.io/api/core/ChangeDetectorRef#detectChangesangular.io/guide/lifecycle-hooks DOM 유지 및 메모리의 서비스는 구성 요소 자체가 종료되는 동안 변경 사항을 적용하려고 시도합니다.
Al-Mothafar

2
이 솔루션은 저에게 효과적이지 않았습니다. 사실 detectChanges 메소드에 대한 코드 주석은 detectChanges가 변경 감지기를 다시 연결할 것이라고 제안하는 것 같습니다. 나에게 유일한 해결책은 tomaszbak의 방법이거나 항상 구독 취소 / clearTimeout / 등이었습니다.
dbandstra

15

당신이 사용할 수있는

this.cdref.markForCheck();

this.cdref.detectChanges(); 많은 경우 대신 . 그러나 가장 좋은 방법은 @ Al-Mothafar 팁을 따르는 것입니다.


7

나는 그것을 해결했다 :

if (!(<ViewRef>this.cd).destroyed) {
   this.cd.detectChanges();
}

허용 된 답변과 거의 동일하지만 이제 필요한 유형 변환을 제공합니다.
electrovir

6

OnDestroy 라이프 사이클 후크에서 ChangeDetectorRef를 분리하고 detectChanges 메소드를 실행하기 전에 ChangeDetectorRef가 파괴되었는지 확인하십시오.

    constructor(private cd: ChangeDetectorRef){}

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

    ngOnDestroy(){
      this.cd.detach();
    }

파괴시 this.cd.detach ()가 필요합니까?
KingMario

구성 요소가 더 이상 렌더링되지 않으면 ChangeDetectorRef를 분리 할 수 ​​있습니다. 필수는 아니지만 이렇게하면 파괴 된 뷰에서 변경 감지가 발생하지 않는지 확인합니다. 반면에 변경 감지가 필요하지 않다고 확신하거나 구성 요소에서 변경 감지를 비활성화해야하는 경우 언제든지 변경 감지를 분리 할 수 ​​있습니다.
Thilina Piyadasun

감사합니다 Thilina. 제 생각에는 this.cd자동 파괴에 분리됩니다. 그렇지 않은 경우 !this.cd['destroyed']이전에 this.cd.detectChanges()에서 테스트 되었으므로 어떤 상황에서도 someFunction안심할 someFunction수 있습니다.
KingMario

5

변수에서 구독자의 값을 가져 와서 동일한 변수로 구독을 취소해야합니다. 다음과 같은 코드를 참조하십시오

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

ngOnDestroy () 메서드의 구독 취소 변경 사항이 있습니다.


4

내 해결책은 모든 관찰자를 구독 취소하는 것이 었습니다.

신청:

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

changeDetector.detach ()를 통한 구독 취소 :

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

그것은 내 코드에 필요했습니다. 또한 ChangeDetectorRef 기능을 사용해야합니다.이 두 가지만 내 코드에 오류가 없습니다.


2

제 경우에는 구성 요소 구성 및 컴파일의 비동기 테스트 설정을 잘못 관리하는 문제였습니다.

  1. 실패한 코드에는 TypeScript Async / Await를 사용하는 beforeEach () 단일 비동기가 있습니다.
  2. 작동시키기 위해 두 개의 beforeEach ()를 사용하고 있는데, 첫 번째는 Angular의 async ()를 사용하여 Async를 처리 하고 두 번째 beforeEach ()는 sync 입니다.

오류를 일으키는 코드 ..

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

수정되었습니다 ...

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

2

특정 질문과는 관련이 없지만 동일한 오류를 검색하여 여기에 도착 했으므로 해결 방법을 공유하겠습니다. 문제는 함수 내에서 테스트를 래핑하지 않고 fixture.detectChanges()내부 fixture.whenStable().then(() => {})를 호출한다는 것 async입니다.

전에:

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

후:

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

1

단순한:

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

1

내 원인은 NgbActiveModal로 모달 대화 상자를 열려고 할 때 발생했습니다. 분명히 .dismiss()자체에서 호출 ngOnInit()하면 이것이 발생합니다.

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

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

해고 전에 틱을 기다리는 것이 해결책이었습니다.

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


1

이 답변은 저에게 도움이되지 않았습니다. 다른 해결책을 찾았습니다.

하위 구성 요소에는 닫기 버튼을 클릭하면 실행되는 출력이 있습니다.

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

그리고 부모 컴포넌트의 "hideChildComponent ()"메서드는 변경 사항을 감지합니다.

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

이것이 누군가를 도울 수 있기를 바랍니다.


1

나를 위해 일한 유일한 해결책은 다음과 같습니다.

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

설명:

  1. 구성 요소가 이전에 파손 된 경우 감지기를 다시 부착하십시오.
  2. 이전 플래그를 잘못된 값으로 설정하십시오.
  3. RxJs 구독을 저장하고 원하는 로직을 내부에 설정하십시오.
  4. 이전에 선언 된 플래그에 의해 구성 요소가 소멸 된 것으로 설정되었는지 여부를 확인하는 조건으로 해당 논리를 래핑합니다.
  5. 해당 블록 내에서 원하는 변경 감지를 수행하십시오.
  6. ngOnDestroy () 메서드를 설정하고 구독을 무효화하고 destroyedComponent 플래그를 정확한 값으로 설정 한 다음 changeDetector를 분리합니다.

1

이 오류를 방지하려면 detectChanges ()를 호출하는 대신 다음과 같이 모델 변경 코드를 래핑 해보십시오.

this.ngZone.run(() => {
      ...
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.