fix(ivy): mark query as dirty upon view insertion (#28429)
PR Close #28429
This commit is contained in:
parent
fdc6e159b4
commit
51a592cdfc
|
@ -191,19 +191,21 @@ function copyQueriesToView(query: LQuery<any>| null): LQuery<any>|null {
|
||||||
|
|
||||||
function insertView(index: number, query: LQuery<any>| null) {
|
function insertView(index: number, query: LQuery<any>| null) {
|
||||||
while (query) {
|
while (query) {
|
||||||
ngDevMode &&
|
ngDevMode && assertViewQueryhasPointerToDeclarationContainer(query);
|
||||||
assertDefined(
|
|
||||||
query.containerValues, 'View queries need to have a pointer to container values.');
|
|
||||||
query.containerValues !.splice(index, 0, query.values);
|
query.containerValues !.splice(index, 0, query.values);
|
||||||
|
|
||||||
|
// mark a query as dirty only when inserted view had matching modes
|
||||||
|
if (query.values.length) {
|
||||||
|
query.list.setDirty();
|
||||||
|
}
|
||||||
|
|
||||||
query = query.next;
|
query = query.next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeView(query: LQuery<any>| null) {
|
function removeView(query: LQuery<any>| null) {
|
||||||
while (query) {
|
while (query) {
|
||||||
ngDevMode &&
|
ngDevMode && assertViewQueryhasPointerToDeclarationContainer(query);
|
||||||
assertDefined(
|
|
||||||
query.containerValues, 'View queries need to have a pointer to container values.');
|
|
||||||
|
|
||||||
const containerValues = query.containerValues !;
|
const containerValues = query.containerValues !;
|
||||||
const viewValuesIdx = containerValues.indexOf(query.values);
|
const viewValuesIdx = containerValues.indexOf(query.values);
|
||||||
|
@ -219,6 +221,9 @@ function removeView(query: LQuery<any>| null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function assertViewQueryhasPointerToDeclarationContainer(query: LQuery<any>) {
|
||||||
|
assertDefined(query.containerValues, 'View queries need to have a pointer to container values.');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterates over local names for a given node and returns directive index
|
* Iterates over local names for a given node and returns directive index
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, ContentChild, ContentChildren, Directive, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef, asNativeElements} from '@angular/core';
|
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, ContentChild, ContentChildren, Directive, QueryList, TemplateRef, Type, ViewChild, ViewChildren, ViewContainerRef, asNativeElements} from '@angular/core';
|
||||||
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
import {ComponentFixture, TestBed, async} from '@angular/core/testing';
|
||||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||||
import {fixmeIvy, ivyEnabled, modifiedInIvy} from '@angular/private/testing';
|
import {fixmeIvy, ivyEnabled, modifiedInIvy, onlyInIvy} from '@angular/private/testing';
|
||||||
import {Subject} from 'rxjs';
|
import {Subject} from 'rxjs';
|
||||||
|
|
||||||
import {stringify} from '../../src/util/stringify';
|
import {stringify} from '../../src/util/stringify';
|
||||||
|
@ -570,7 +570,7 @@ describe('Query API', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note: this test is just document our current behavior, which we do for performance reasons.
|
// Note: this test is just document our current behavior, which we do for performance reasons.
|
||||||
fixmeIvy('FW-853: Query results are cleared if embedded views are detached / moved')
|
modifiedInIvy('Query results from views are reported upon view insert / detach')
|
||||||
.it('should not affect queries for projected templates if views are detached or moved',
|
.it('should not affect queries for projected templates if views are detached or moved',
|
||||||
() => {
|
() => {
|
||||||
const template = `<manual-projecting #q>
|
const template = `<manual-projecting #q>
|
||||||
|
@ -600,6 +600,41 @@ describe('Query API', () => {
|
||||||
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2']);
|
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onlyInIvy('Query results from views are reported upon view insert / detach')
|
||||||
|
.it('should update queries when a view is detached and re-inserted', () => {
|
||||||
|
const template = `<manual-projecting #q>
|
||||||
|
<ng-template let-x="x">
|
||||||
|
<div [text]="x"></div>
|
||||||
|
</ng-template>
|
||||||
|
</manual-projecting>`;
|
||||||
|
const view = createTestCmpAndDetectChanges(MyComp0, template);
|
||||||
|
const q = view.debugElement.children[0].references !['q'] as ManualProjecting;
|
||||||
|
expect(q.query.length).toBe(0);
|
||||||
|
|
||||||
|
const view1 = q.vc.createEmbeddedView(q.template, {'x': '1'});
|
||||||
|
const view2 = q.vc.createEmbeddedView(q.template, {'x': '2'});
|
||||||
|
|
||||||
|
// 2 views were created and inserted so we've got 2 matching results
|
||||||
|
view.detectChanges();
|
||||||
|
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['1', '2']);
|
||||||
|
|
||||||
|
q.vc.detach(1);
|
||||||
|
q.vc.detach(0);
|
||||||
|
|
||||||
|
// both views were detached so query results from those views should not be reported
|
||||||
|
view.detectChanges();
|
||||||
|
expect(q.query.map((d: TextDirective) => d.text)).toEqual([]);
|
||||||
|
|
||||||
|
q.vc.insert(view2);
|
||||||
|
q.vc.insert(view1);
|
||||||
|
|
||||||
|
// previously detached views are re-inserted in the different order so:
|
||||||
|
// - query results from the inserted views are reported again
|
||||||
|
// - the order results from views reflects orders of views
|
||||||
|
view.detectChanges();
|
||||||
|
expect(q.query.map((d: TextDirective) => d.text)).toEqual(['2', '1']);
|
||||||
|
});
|
||||||
|
|
||||||
fixmeIvy('FW-920: Queries in nested views are not destroyed properly')
|
fixmeIvy('FW-920: Queries in nested views are not destroyed properly')
|
||||||
.it('should remove manually projected templates if their parent view is destroyed', () => {
|
.it('should remove manually projected templates if their parent view is destroyed', () => {
|
||||||
const template = `
|
const template = `
|
||||||
|
|
Loading…
Reference in New Issue