fix(core): error when invoking callbacks registered via ViewRef.onDestroy (#37543)
Invoking a callback registered through `ViewRef.onDestroy` throws an error, because we weren't registering it correctly in the internal data structure. These changes also remove the `storeCleanupFn` function, because it was mostly identical to `storeCleanupWithContext` and was only used in one place. Fixes #36213. PR Close #37543
This commit is contained in:
parent
c00f4ab2ae
commit
543b679762
|
@ -795,22 +795,6 @@ export function storeCleanupWithContext(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the cleanup function itself in LView.cleanupInstances.
|
|
||||||
*
|
|
||||||
* This is necessary for functions that are wrapped with their contexts, like in renderer2
|
|
||||||
* listeners.
|
|
||||||
*
|
|
||||||
* On the first template pass, the index of the cleanup function is saved in TView.
|
|
||||||
*/
|
|
||||||
export function storeCleanupFn(tView: TView, lView: LView, cleanupFn: Function): void {
|
|
||||||
getLCleanup(lView).push(cleanupFn);
|
|
||||||
|
|
||||||
if (tView.firstCreatePass) {
|
|
||||||
getTViewCleanup(tView).push(lView[CLEANUP]!.length - 1, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a TNode object from the arguments.
|
* Constructs a TNode object from the arguments.
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detec
|
||||||
import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_container_ref';
|
import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_container_ref';
|
||||||
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref';
|
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, InternalViewRef as viewEngine_InternalViewRef} from '../linker/view_ref';
|
||||||
import {assertDefined} from '../util/assert';
|
import {assertDefined} from '../util/assert';
|
||||||
import {checkNoChangesInRootView, checkNoChangesInternal, detectChangesInRootView, detectChangesInternal, markViewDirty, storeCleanupFn} from './instructions/shared';
|
import {checkNoChangesInRootView, checkNoChangesInternal, detectChangesInRootView, detectChangesInternal, markViewDirty, storeCleanupWithContext} from './instructions/shared';
|
||||||
import {CONTAINER_HEADER_OFFSET} from './interfaces/container';
|
import {CONTAINER_HEADER_OFFSET} from './interfaces/container';
|
||||||
import {TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
|
import {TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
|
||||||
import {isLContainer} from './interfaces/type_checks';
|
import {isLContainer} from './interfaces/type_checks';
|
||||||
|
@ -88,7 +88,7 @@ export class ViewRef<T> implements viewEngine_EmbeddedViewRef<T>, viewEngine_Int
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy(callback: Function) {
|
onDestroy(callback: Function) {
|
||||||
storeCleanupFn(this._lView[TVIEW], this._lView, callback);
|
storeCleanupWithContext(this._lView[TVIEW], this._lView, null, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ApplicationRef, Component, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, NgModule} from '@angular/core';
|
import {ApplicationRef, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, NgModule} from '@angular/core';
|
||||||
import {InternalViewRef} from '@angular/core/src/linker/view_ref';
|
import {InternalViewRef} from '@angular/core/src/linker/view_ref';
|
||||||
import {TestBed} from '@angular/core/testing';
|
import {TestBed} from '@angular/core/testing';
|
||||||
|
|
||||||
|
@ -54,4 +54,22 @@ describe('ViewRef', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
expect(document.body.querySelector('dynamic-cpt')).toBeFalsy();
|
expect(document.body.querySelector('dynamic-cpt')).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should invoke the onDestroy callback of a view ref', () => {
|
||||||
|
let called = false;
|
||||||
|
|
||||||
|
@Component({template: ''})
|
||||||
|
class App {
|
||||||
|
constructor(changeDetectorRef: ChangeDetectorRef) {
|
||||||
|
(changeDetectorRef as InternalViewRef).onDestroy(() => called = true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({declarations: [App]});
|
||||||
|
const fixture = TestBed.createComponent(App);
|
||||||
|
fixture.detectChanges();
|
||||||
|
fixture.destroy();
|
||||||
|
|
||||||
|
expect(called).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue