fix(ivy): reset binding index before executing a template in `refreshView` call (#32201)
Prior to this change, the `BINDING_INDEX` of a given lView was reset after processing a template. However change detection can be triggered as a result of View queries processing, thus leading to subsequent `refreshView` call (and executing a template), which in turn operates with the binding index that is not reset after the previous `refreshView` call. This commit updates the logic to reset binding index before we execute a template, so binding index is correct for instructions inside template function. PR Close #32201
This commit is contained in:
parent
4f7c971ee7
commit
6b245a39ee
|
@ -377,14 +377,14 @@ export function refreshView<T>(
|
|||
try {
|
||||
resetPreOrderHookFlags(lView);
|
||||
|
||||
if (templateFn !== null) {
|
||||
executeTemplate(lView, templateFn, RenderFlags.Update, context);
|
||||
}
|
||||
|
||||
// Resetting the bindingIndex of the current LView as the next steps may trigger change
|
||||
// detection.
|
||||
lView[BINDING_INDEX] = tView.bindingStartIndex;
|
||||
|
||||
if (templateFn !== null) {
|
||||
executeTemplate(lView, templateFn, RenderFlags.Update, context);
|
||||
}
|
||||
|
||||
const checkNoChangesMode = getCheckNoChangesMode();
|
||||
const hooksInitPhaseCompleted =
|
||||
(flags & LViewFlags.InitPhaseStateMask) === InitPhaseState.InitPhaseCompleted;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {ApplicationRef, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Directive, DoCheck, EmbeddedViewRef, ErrorHandler, Input, NgModule, OnInit, TemplateRef, Type, ViewChild, ViewContainerRef} from '@angular/core';
|
||||
import {ApplicationRef, ChangeDetectionStrategy, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Directive, DoCheck, EmbeddedViewRef, ErrorHandler, Input, NgModule, OnInit, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||
|
||||
|
@ -545,6 +545,44 @@ describe('change detection', () => {
|
|||
expect(fixture.nativeElement.textContent).toEqual('1');
|
||||
});
|
||||
|
||||
it('should support change detection triggered as a result of View queries processing', () => {
|
||||
@Component({
|
||||
selector: 'app',
|
||||
template: `
|
||||
<div *ngIf="visible" #ref>Visible text</div>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
@ViewChildren('ref')
|
||||
ref !: QueryList<any>;
|
||||
|
||||
visible = false;
|
||||
|
||||
constructor(public changeDetectorRef: ChangeDetectorRef) {}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.ref.changes.subscribe((refs: QueryList<any>) => {
|
||||
this.visible = false;
|
||||
this.changeDetectorRef.detectChanges();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App],
|
||||
imports: [CommonModule],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.textContent).toBe('');
|
||||
|
||||
// even though we set "visible" to `true`, we do not expect any content to be displayed,
|
||||
// since the flag is overridden in `ngAfterViewInit` back to `false`
|
||||
fixture.componentInstance.visible = true;
|
||||
fixture.detectChanges();
|
||||
expect(fixture.nativeElement.textContent).toBe('');
|
||||
});
|
||||
|
||||
describe('dynamic views', () => {
|
||||
@Component({selector: 'structural-comp', template: '{{ value }}'})
|
||||
class StructuralComp {
|
||||
|
|
Loading…
Reference in New Issue