fix(ivy): attached flag not being reset when view is destroyed (#29064)
Currently we only reset the `Attached` flag of a view if it is detached through its parent, however this means that if a root view is destroyed, its flag will never be reset. This manifested itself in one of the Material tests where we were destroying the root view. This PR resolves FW-1130. PR Close #29064
This commit is contained in:
parent
a06824aef6
commit
c0757d1d44
|
@ -426,6 +426,10 @@ function cleanUpView(viewOrContainer: LView | LContainer): void {
|
|||
if ((viewOrContainer as LView).length >= HEADER_OFFSET) {
|
||||
const view = viewOrContainer as LView;
|
||||
|
||||
// Usually the Attached flag is removed when the view is detached from its parent, however
|
||||
// if it's a root view, the flag won't be unset hence why we're also removing on destroy.
|
||||
view[FLAGS] &= ~LViewFlags.Attached;
|
||||
|
||||
// Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook
|
||||
// runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If
|
||||
// We don't flag the view as destroyed before the hooks, this could lead to an infinite loop.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {Component, Directive, HostBinding, HostListener, QueryList, ViewChildren} from '@angular/core';
|
||||
import {Component, Directive, HostBinding, HostListener, Input, QueryList, ViewChildren} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
@ -111,4 +111,40 @@ describe('acceptance integration tests', () => {
|
|||
expect(element.classList.contains('foo')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not set inputs after destroy', () => {
|
||||
@Directive({
|
||||
selector: '[no-assign-after-destroy]',
|
||||
})
|
||||
class NoAssignAfterDestroy {
|
||||
private _isDestroyed = false;
|
||||
|
||||
@Input()
|
||||
get value() { return this._value; }
|
||||
set value(newValue: any) {
|
||||
if (this._isDestroyed) {
|
||||
throw Error('Cannot assign to value after destroy.');
|
||||
}
|
||||
|
||||
this._value = newValue;
|
||||
}
|
||||
private _value: any;
|
||||
|
||||
ngOnDestroy() { this._isDestroyed = true; }
|
||||
}
|
||||
|
||||
@Component({template: '<div no-assign-after-destroy [value]="directiveValue"></div>'})
|
||||
class App {
|
||||
directiveValue = 'initial-value';
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [NoAssignAfterDestroy, App]});
|
||||
let fixture = TestBed.createComponent(App);
|
||||
fixture.destroy();
|
||||
|
||||
expect(() => {
|
||||
fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -361,10 +361,6 @@ window.testBlocklist = {
|
|||
"error": "Error: Expected 'none' to be falsy.",
|
||||
"notes": "Unknown"
|
||||
},
|
||||
"MatCalendar calendar with min and max date should update the minDate in the child view if it changed after an interaction": {
|
||||
"error": "Error: This PortalOutlet has already been disposed",
|
||||
"notes": "Unknown"
|
||||
},
|
||||
"MatTable with basic data source should be able to create a table with the right content and without when row": {
|
||||
"error": "TypeError: Cannot read property 'querySelectorAll' of null",
|
||||
"notes": "Unknown"
|
||||
|
|
Loading…
Reference in New Issue