尝试使用已销毁的视图:detectChanges
Attempt to use a destroyed view: detectChanges
我正在使用 Angular Meteor 2 创建一个简单的 UI。
1) 我有一个顶部导航栏组件,它有一个 'logout' 按钮。
2) 单击 'logout' 按钮时,它会重定向到 'login'.
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
顶部-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()
,因为更改已经完成,并且在组件的销毁阶段调用了方法。
所以你需要让你的组件implements OnDestroy
,然后你需要取消让this.ref.detectChanges()
被调用的改变。所以你的 TopNavbarComponent
必须类似于:
export class TopNavbarComponent implements OnDestroy {
// ... your code
ngOnDestroy() {
this.cdRef.detach(); // do this
// for me I was detecting changes using `detectChanges()` inside a subscription with `subscribe()` to observable without limitation, so was enough for me to just `unsubscribe()` like the following line;
// this.authObserver.unsubscribe();
}
}
P.S:不要忘记 unsubscribe()
组件中的所有观察者!无论如何你必须这样做,订阅而不取消订阅可能是包括这个在内的数百个问题的主要原因,请参阅
编辑:
我知道网络上的其他解决方案试图通过处理错误本身来解决问题,而最佳做法是了解问题的根源,检查视图是否被破坏是一个很好的解决方案恕我直言,因为原始原因可能是内存泄漏背后的问题,谁知道呢!所以问题的根源是需要终止 运行 服务,而不是在不知道问题根源的情况下尝试终止错误本身,例如,运行 订阅(尤其是您的自定义订阅)必须关闭。
所以!家务管理的东西是更好的性能所必需的,它并不总是一个更简单和更快的解决方案是更好的解决方案,如果你把污垢藏在地毯下并不意味着你“打扫”了你的房间,即使它看起来确实不错 :)
您必须在变量中获取订阅者的值并通过相同的变量取消订阅。请参考以下相同代码
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() 中取消订阅发生了变化。
唯一对我有用的解决方案是:
if (!this.changeDetectionRef['destroyed']) {
this.changeDetectionRef.detectChanges();
}
您可以使用
this.cdref.markForCheck();
而不是
this.cdref.detectChanges();
在许多情况下。但最好的方法是遵循@Al-Mothafar 的提示
就我而言,问题是组件配置和编译的异步测试设置管理不善。
- 失败的代码在使用 TypeScript Async/Await
之前有一个单一的异步 beforeEach()
- 为了使其正常工作,我使用了两个 beforeEach(),其中第一个使用 Angular's async(), and the second beforeEach() is 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();
});
与具体问题关系不大,但我通过谷歌搜索同样的错误来到这里,所以我将分享我的解决方法。问题是我在 fixture.whenStable().then(() => {})
中调用 fixture.detectChanges()
而没有将测试包装在 async
函数中。
之前:
it('should...', () => {
fixture.whenStable().then(() => {
fixture.detectChanges();
});
});
之后:
it('should...', async(() => {
fixture.whenStable().then(() => {
fixture.detectChanges();
});
}));
这个答案对我没有帮助。我找到了其他解决方案。
子组件具有在单击关闭按钮时触发的输出
<child-component
*ngIf="childComponentIsShown"
(formCloseEmitter)="hideChildComponent()"
></child-component>
父组件中的 "hideChildComponent()" 方法检测更改。
hideChildComponent() {
this.childComponentIsShown = false;
this.cdr.detectChanges();
}
希望这会对某人有所帮助。
我的解决方案是取消订阅所有观察者。
订阅:
ngOnInit() {
this._currentUserSubscription = this._auth.currentUser.subscribe(currentUser => {});
}
使用 changeDetector.detach() 退订:
ngOnDestroy() {
this._currentUserSubscription.unsubscribe();
this._cdRef.detach();
}
这是我的代码所必需的,我还必须使用 ChangeDetectorRef 功能,只有这两个东西使我的代码没有错误。
简单:
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();
}
我已经解决了:
if (!(<ViewRef>this.cd).destroyed) {
this.cd.detectChanges();
}
我的原因发生在我试图用 NgbActiveModal 打开模式对话框时。显然从它自己的 ngOnInit()
调用 .dismiss()
会导致这个。
export class MyModal {
constructor(private modalInstance: NgbActiveModal) {
}
ngOnInit() {
if (foo) this.modalInstance.dismiss();
}
解决方案是在解雇前等待滴答声。
if (foo) setTimeout(() => this.modalInstance.dismiss());
对我来说,唯一有效的解决方案如下:
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();
}
说明:
- 如果组件之前已损坏,请重新连接探测器。
- 将之前的标志设置为假值。
- 保存 RxJs 订阅,并在里面设置你想要的逻辑。
- 将该逻辑包装在一个条件中,该条件检查组件是否已被先前声明的标志设置为已销毁。
- 对该块内的更改执行所需的检测。
- 设置 ngOnDestroy() 方法并取消订阅,将 destroyedComponent 标志设置为真值,并分离 changeDetector。
只需在 OnDestroy 生命周期挂钩上分离 ChangeDetectorRef 并在执行 detectChanges 方法之前检查 ChangeDetectorRef 是否被销毁
constructor(private cd: ChangeDetectorRef){}
someFunction(){
if(!this.cd['destroyed']){
this.cd.detectChanges();
}
}
ngOnDestroy(){
this.cd.detach();
}
为避免此错误,请尝试通过以下方式包装模型更改代码,而不是调用 detectChanges():
this.ngZone.run(() => {
...
});
我正在使用 Angular Meteor 2 创建一个简单的 UI。
1) 我有一个顶部导航栏组件,它有一个 'logout' 按钮。
2) 单击 'logout' 按钮时,它会重定向到 'login'.
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
顶部-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()
,因为更改已经完成,并且在组件的销毁阶段调用了方法。
所以你需要让你的组件implements OnDestroy
,然后你需要取消让this.ref.detectChanges()
被调用的改变。所以你的 TopNavbarComponent
必须类似于:
export class TopNavbarComponent implements OnDestroy {
// ... your code
ngOnDestroy() {
this.cdRef.detach(); // do this
// for me I was detecting changes using `detectChanges()` inside a subscription with `subscribe()` to observable without limitation, so was enough for me to just `unsubscribe()` like the following line;
// this.authObserver.unsubscribe();
}
}
P.S:不要忘记 unsubscribe()
组件中的所有观察者!无论如何你必须这样做,订阅而不取消订阅可能是包括这个在内的数百个问题的主要原因,请参阅
编辑: 我知道网络上的其他解决方案试图通过处理错误本身来解决问题,而最佳做法是了解问题的根源,检查视图是否被破坏是一个很好的解决方案恕我直言,因为原始原因可能是内存泄漏背后的问题,谁知道呢!所以问题的根源是需要终止 运行 服务,而不是在不知道问题根源的情况下尝试终止错误本身,例如,运行 订阅(尤其是您的自定义订阅)必须关闭。
所以!家务管理的东西是更好的性能所必需的,它并不总是一个更简单和更快的解决方案是更好的解决方案,如果你把污垢藏在地毯下并不意味着你“打扫”了你的房间,即使它看起来确实不错 :)
您必须在变量中获取订阅者的值并通过相同的变量取消订阅。请参考以下相同代码
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() 中取消订阅发生了变化。
唯一对我有用的解决方案是:
if (!this.changeDetectionRef['destroyed']) {
this.changeDetectionRef.detectChanges();
}
您可以使用
this.cdref.markForCheck();
而不是
this.cdref.detectChanges();
在许多情况下。但最好的方法是遵循@Al-Mothafar 的提示
就我而言,问题是组件配置和编译的异步测试设置管理不善。
- 失败的代码在使用 TypeScript Async/Await 之前有一个单一的异步 beforeEach()
- 为了使其正常工作,我使用了两个 beforeEach(),其中第一个使用 Angular's async(), and the second beforeEach() is 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();
});
与具体问题关系不大,但我通过谷歌搜索同样的错误来到这里,所以我将分享我的解决方法。问题是我在 fixture.whenStable().then(() => {})
中调用 fixture.detectChanges()
而没有将测试包装在 async
函数中。
之前:
it('should...', () => {
fixture.whenStable().then(() => {
fixture.detectChanges();
});
});
之后:
it('should...', async(() => {
fixture.whenStable().then(() => {
fixture.detectChanges();
});
}));
这个答案对我没有帮助。我找到了其他解决方案。
子组件具有在单击关闭按钮时触发的输出
<child-component
*ngIf="childComponentIsShown"
(formCloseEmitter)="hideChildComponent()"
></child-component>
父组件中的 "hideChildComponent()" 方法检测更改。
hideChildComponent() {
this.childComponentIsShown = false;
this.cdr.detectChanges();
}
希望这会对某人有所帮助。
我的解决方案是取消订阅所有观察者。
订阅:
ngOnInit() {
this._currentUserSubscription = this._auth.currentUser.subscribe(currentUser => {});
}
使用 changeDetector.detach() 退订:
ngOnDestroy() {
this._currentUserSubscription.unsubscribe();
this._cdRef.detach();
}
这是我的代码所必需的,我还必须使用 ChangeDetectorRef 功能,只有这两个东西使我的代码没有错误。
简单:
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();
}
我已经解决了:
if (!(<ViewRef>this.cd).destroyed) {
this.cd.detectChanges();
}
我的原因发生在我试图用 NgbActiveModal 打开模式对话框时。显然从它自己的 ngOnInit()
调用 .dismiss()
会导致这个。
export class MyModal {
constructor(private modalInstance: NgbActiveModal) {
}
ngOnInit() {
if (foo) this.modalInstance.dismiss();
}
解决方案是在解雇前等待滴答声。
if (foo) setTimeout(() => this.modalInstance.dismiss());
对我来说,唯一有效的解决方案如下:
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();
}
说明:
- 如果组件之前已损坏,请重新连接探测器。
- 将之前的标志设置为假值。
- 保存 RxJs 订阅,并在里面设置你想要的逻辑。
- 将该逻辑包装在一个条件中,该条件检查组件是否已被先前声明的标志设置为已销毁。
- 对该块内的更改执行所需的检测。
- 设置 ngOnDestroy() 方法并取消订阅,将 destroyedComponent 标志设置为真值,并分离 changeDetector。
只需在 OnDestroy 生命周期挂钩上分离 ChangeDetectorRef 并在执行 detectChanges 方法之前检查 ChangeDetectorRef 是否被销毁
constructor(private cd: ChangeDetectorRef){}
someFunction(){
if(!this.cd['destroyed']){
this.cd.detectChanges();
}
}
ngOnDestroy(){
this.cd.detach();
}
为避免此错误,请尝试通过以下方式包装模型更改代码,而不是调用 detectChanges():
this.ngZone.run(() => {
...
});