fix(ivy): clone queries correctly for multiple component instances (#27892)
When requesting a queries instance for a node, it was previously decided whether it needs to be cloned if the node was not already marked as hosting a query. This check is in place to have only a single queries instance per node. The issue with this approach is that no clone is created for subsequent instantiations of a component, as the TNode is already marked as hosting a query during first template pass, whereas the cloning of queries should be independent of first template pass. To overcome this issue, the queries are assigned an owner TNode such that it can reliably be determined if a clone needs to be created. PR Close #27892
This commit is contained in:
@ -2604,6 +2604,64 @@ describe('query', () => {
|
||||
expect(inInstance !.fooBars.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should support nested shallow content queries across multiple component instances', () => {
|
||||
let outInstance: QueryDirective;
|
||||
let inInstance: QueryDirective;
|
||||
|
||||
class QueryDirective {
|
||||
fooBars: any;
|
||||
static ngDirectiveDef = defineDirective({
|
||||
type: QueryDirective,
|
||||
selectors: [['', 'query', '']],
|
||||
exportAs: ['query'],
|
||||
factory: () => new QueryDirective(),
|
||||
contentQueries: (dirIndex) => {
|
||||
// @ContentChildren('foo', {descendants: true}) fooBars:
|
||||
// QueryList<ElementRef>;
|
||||
registerContentQuery(query(null, ['foo'], false), dirIndex);
|
||||
},
|
||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
||||
let tmp: any;
|
||||
const instance = load<QueryDirective>(dirIndex);
|
||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
||||
(instance.fooBars = tmp);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const AppComponent = createComponent(
|
||||
'app-component',
|
||||
/**
|
||||
* <div query #out="query">
|
||||
* <div query #in="query" #foo>
|
||||
* <span #foo></span>
|
||||
* </div>
|
||||
* </div>
|
||||
*/
|
||||
function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
elementStart(0, 'div', ['query', ''], ['out', 'query']);
|
||||
{ element(2, 'div', ['query', ''], ['in', 'query', 'foo', '']); }
|
||||
elementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
outInstance = load<QueryDirective>(1);
|
||||
inInstance = load<QueryDirective>(3);
|
||||
}
|
||||
},
|
||||
5, 0, [QueryDirective]);
|
||||
|
||||
const fixture1 = new ComponentFixture(AppComponent);
|
||||
expect(outInstance !.fooBars.length).toBe(1);
|
||||
expect(inInstance !.fooBars.length).toBe(1);
|
||||
|
||||
outInstance = inInstance = null !;
|
||||
|
||||
const fixture2 = new ComponentFixture(AppComponent);
|
||||
expect(outInstance !.fooBars.length).toBe(1);
|
||||
expect(inInstance !.fooBars.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should respect shallow flag on content queries when mixing deep and shallow queries',
|
||||
() => {
|
||||
class ShallowQueryDirective {
|
||||
|
Reference in New Issue
Block a user