Skip to content

Commit c0757d1

Browse files
crisbetoAndrewKushnir
authored andcommitted
fix(ivy): attached flag not being reset when view is destroyed (angular#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 angular#29064
1 parent a06824a commit c0757d1

File tree

3 files changed

+41
-5
lines changed

3 files changed

+41
-5
lines changed

packages/core/src/render3/node_manipulation.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,10 @@ function cleanUpView(viewOrContainer: LView | LContainer): void {
426426
if ((viewOrContainer as LView).length >= HEADER_OFFSET) {
427427
const view = viewOrContainer as LView;
428428

429+
// Usually the Attached flag is removed when the view is detached from its parent, however
430+
// if it's a root view, the flag won't be unset hence why we're also removing on destroy.
431+
view[FLAGS] &= ~LViewFlags.Attached;
432+
429433
// Mark the LView as destroyed *before* executing the onDestroy hooks. An onDestroy hook
430434
// runs arbitrary user code, which could include its own `viewRef.destroy()` (or similar). If
431435
// We don't flag the view as destroyed before the hooks, this could lead to an infinite loop.

packages/core/test/acceptance/integration_spec.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import {Component, Directive, HostBinding, HostListener, QueryList, ViewChildren} from '@angular/core';
8+
import {Component, Directive, HostBinding, HostListener, Input, QueryList, ViewChildren} from '@angular/core';
99
import {TestBed} from '@angular/core/testing';
1010
import {By} from '@angular/platform-browser';
1111
import {expect} from '@angular/platform-browser/testing/src/matchers';
@@ -111,4 +111,40 @@ describe('acceptance integration tests', () => {
111111
expect(element.classList.contains('foo')).toBeTruthy();
112112
});
113113

114+
it('should not set inputs after destroy', () => {
115+
@Directive({
116+
selector: '[no-assign-after-destroy]',
117+
})
118+
class NoAssignAfterDestroy {
119+
private _isDestroyed = false;
120+
121+
@Input()
122+
get value() { return this._value; }
123+
set value(newValue: any) {
124+
if (this._isDestroyed) {
125+
throw Error('Cannot assign to value after destroy.');
126+
}
127+
128+
this._value = newValue;
129+
}
130+
private _value: any;
131+
132+
ngOnDestroy() { this._isDestroyed = true; }
133+
}
134+
135+
@Component({template: '<div no-assign-after-destroy [value]="directiveValue"></div>'})
136+
class App {
137+
directiveValue = 'initial-value';
138+
}
139+
140+
TestBed.configureTestingModule({declarations: [NoAssignAfterDestroy, App]});
141+
let fixture = TestBed.createComponent(App);
142+
fixture.destroy();
143+
144+
expect(() => {
145+
fixture = TestBed.createComponent(App);
146+
fixture.detectChanges();
147+
}).not.toThrow();
148+
});
149+
114150
});

tools/material-ci/angular_material_test_blocklist.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,10 +361,6 @@ window.testBlocklist = {
361361
"error": "Error: Expected 'none' to be falsy.",
362362
"notes": "Unknown"
363363
},
364-
"MatCalendar calendar with min and max date should update the minDate in the child view if it changed after an interaction": {
365-
"error": "Error: This PortalOutlet has already been disposed",
366-
"notes": "Unknown"
367-
},
368364
"MatTable with basic data source should be able to create a table with the right content and without when row": {
369365
"error": "TypeError: Cannot read property 'querySelectorAll' of null",
370366
"notes": "Unknown"

0 commit comments

Comments
 (0)