fix(ivy): Content Queries inheritance fix (#28324)
Prior to this change contentQueriesRefresh functions that represent refresh logic for @ContentQuery list were not composable, which caused problems in case one Directive inherits another one and both of them contain Content Queries. Due to the fact that we used indices to reference queries in refresh function, results were placed into wrong Queries. In order to avoid that we no longer use indices to reference queries and instead maintain current content query index while iterating through them. This allows us to compose contentQueriesRefresh functions and make inheritance feature work with Content Queries. PR Close #28324
This commit is contained in:
parent
ebac5dba38
commit
bb94434d85
|
@ -1554,14 +1554,14 @@ describe('compiler compliance', () => {
|
||||||
return new (t || ContentQueryComponent)();
|
return new (t || ContentQueryComponent)();
|
||||||
},
|
},
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery(SomeDirective, true), dirIndex);
|
$r3$.ɵcontentQuery(dirIndex, SomeDirective, true);
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery(SomeDirective, false), dirIndex);
|
$r3$.ɵcontentQuery(dirIndex, SomeDirective, false);
|
||||||
},
|
},
|
||||||
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
|
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex) {
|
||||||
const instance = $r3$.ɵload(dirIndex);
|
const instance = $r3$.ɵload(dirIndex);
|
||||||
var $tmp$;
|
var $tmp$;
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && ($instance$.someDir = $tmp$.first));
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && ($instance$.someDir = $tmp$.first));
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && ($instance$.someDirList = $tmp$));
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && ($instance$.someDirList = $tmp$));
|
||||||
},
|
},
|
||||||
ngContentSelectors: _c0,
|
ngContentSelectors: _c0,
|
||||||
consts: 2,
|
consts: 2,
|
||||||
|
@ -1613,14 +1613,14 @@ describe('compiler compliance', () => {
|
||||||
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
…
|
…
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery($e0_attrs$, true), dirIndex);
|
$r3$.ɵcontentQuery(dirIndex, $e0_attrs$, true);
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery($e1_attrs$, false), dirIndex);
|
$r3$.ɵcontentQuery(dirIndex, $e1_attrs$, false);
|
||||||
},
|
},
|
||||||
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
|
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex) {
|
||||||
const instance = $r3$.ɵload(dirIndex);
|
const instance = $r3$.ɵload(dirIndex);
|
||||||
var $tmp$;
|
var $tmp$;
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (instance.myRef = $tmp$.first));
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.myRefs = $tmp$));
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (instance.myRefs = $tmp$));
|
||||||
},
|
},
|
||||||
…
|
…
|
||||||
});`;
|
});`;
|
||||||
|
@ -1666,18 +1666,18 @@ describe('compiler compliance', () => {
|
||||||
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
|
||||||
…
|
…
|
||||||
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
|
contentQueries: function ContentQueryComponent_ContentQueries(dirIndex) {
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery($e0_attrs$ , true, TemplateRef), dirIndex);
|
$r3$.ɵcontentQuery(dirIndex, $e0_attrs$ , true, TemplateRef);
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery(SomeDirective, true, ElementRef), dirIndex);
|
$r3$.ɵcontentQuery(dirIndex, SomeDirective, true, ElementRef);
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery($e1_attrs$, false, ElementRef), dirIndex);
|
$r3$.ɵcontentQuery(dirIndex, $e1_attrs$, false, ElementRef);
|
||||||
$r3$.ɵregisterContentQuery($r3$.ɵquery(SomeDirective, false, TemplateRef), dirIndex);
|
$r3$.ɵcontentQuery(dirIndex, SomeDirective, false, TemplateRef);
|
||||||
},
|
},
|
||||||
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
|
contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex) {
|
||||||
const instance = $r3$.ɵload(dirIndex);
|
const instance = $r3$.ɵload(dirIndex);
|
||||||
var $tmp$;
|
var $tmp$;
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (instance.myRef = $tmp$.first));
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.someDir = $tmp$.first));
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (instance.someDir = $tmp$.first));
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 2)))) && (instance.myRefs = $tmp$));
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (instance.myRefs = $tmp$));
|
||||||
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 3)))) && (instance.someDirs = $tmp$));
|
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (instance.someDirs = $tmp$));
|
||||||
},
|
},
|
||||||
…
|
…
|
||||||
});`;
|
});`;
|
||||||
|
|
|
@ -12,6 +12,18 @@ import {NgtscTestEnvironment} from './env';
|
||||||
|
|
||||||
const trim = (input: string): string => input.replace(/\s+/g, ' ').trim();
|
const trim = (input: string): string => input.replace(/\s+/g, ' ').trim();
|
||||||
|
|
||||||
|
const varRegExp = (name: string): RegExp => new RegExp(`var \\w+ = \\[\"${name}\"\\];`);
|
||||||
|
|
||||||
|
const viewQueryRegExp = (descend: boolean, ref?: string): RegExp => {
|
||||||
|
const maybeRef = ref ? `, ${ref}` : ``;
|
||||||
|
return new RegExp(`i0\\.ɵviewQuery\\(\\w+, ${descend}${maybeRef}\\)`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const contentQueryRegExp = (predicate: string, descend: boolean, ref?: string): RegExp => {
|
||||||
|
const maybeRef = ref ? `, ${ref}` : ``;
|
||||||
|
return new RegExp(`i0\\.ɵcontentQuery\\(dirIndex, ${predicate}, ${descend}${maybeRef}\\)`);
|
||||||
|
};
|
||||||
|
|
||||||
describe('ngtsc behavioral tests', () => {
|
describe('ngtsc behavioral tests', () => {
|
||||||
if (!NgtscTestEnvironment.supported) {
|
if (!NgtscTestEnvironment.supported) {
|
||||||
// These tests should be excluded from the non-Bazel build.
|
// These tests should be excluded from the non-Bazel build.
|
||||||
|
@ -706,14 +718,6 @@ describe('ngtsc behavioral tests', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate queries for components', () => {
|
it('should generate queries for components', () => {
|
||||||
|
|
||||||
// Helper functions to construct RegExps for output validation
|
|
||||||
const varRegExp = (name: string): RegExp => new RegExp(`var \\w+ = \\[\"${name}\"\\];`);
|
|
||||||
const queryRegExp = (fnName: string, descend: boolean, ref?: string | null): RegExp => {
|
|
||||||
const maybeRef = ref ? `, ${ref}` : ``;
|
|
||||||
return new RegExp(`i0\\.ɵ${fnName}\\(\\w+, ${descend}${maybeRef}\\)`);
|
|
||||||
};
|
|
||||||
|
|
||||||
env.tsconfig();
|
env.tsconfig();
|
||||||
env.write(`test.ts`, `
|
env.write(`test.ts`, `
|
||||||
import {Component, ContentChild, ContentChildren, TemplateRef, ViewChild} from '@angular/core';
|
import {Component, ContentChild, ContentChildren, TemplateRef, ViewChild} from '@angular/core';
|
||||||
|
@ -740,23 +744,10 @@ describe('ngtsc behavioral tests', () => {
|
||||||
expect(jsContents).toMatch(varRegExp('test1'));
|
expect(jsContents).toMatch(varRegExp('test1'));
|
||||||
expect(jsContents).toMatch(varRegExp('test2'));
|
expect(jsContents).toMatch(varRegExp('test2'));
|
||||||
expect(jsContents).toMatch(varRegExp('accessor'));
|
expect(jsContents).toMatch(varRegExp('accessor'));
|
||||||
expect(jsContents).toContain(`i0.ɵquery(TemplateRef, false)`);
|
// match `i0.ɵcontentQuery(dirIndex, _c1, true, TemplateRef)`
|
||||||
expect(jsContents)
|
expect(jsContents).toMatch(contentQueryRegExp('\\w+', true, 'TemplateRef'));
|
||||||
.toMatch(
|
// match `i0.ɵviewQuery(_c2, true)`
|
||||||
// match `i0.ɵquery(_c0, true, TemplateRef)`
|
expect(jsContents).toMatch(viewQueryRegExp(true));
|
||||||
queryRegExp('query', true, 'TemplateRef'));
|
|
||||||
expect(jsContents)
|
|
||||||
.toMatch(
|
|
||||||
// match `i0.ɵquery(_c0, true)`
|
|
||||||
queryRegExp('query', true));
|
|
||||||
expect(jsContents)
|
|
||||||
.toMatch(
|
|
||||||
// match `i0.ɵviewQuery(_c0, true)`
|
|
||||||
queryRegExp('viewQuery', true));
|
|
||||||
expect(jsContents)
|
|
||||||
.toMatch(
|
|
||||||
// match `i0.ɵviewQuery(_c0, true)`
|
|
||||||
queryRegExp('viewQuery', true));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle queries that use forwardRef', () => {
|
it('should handle queries that use forwardRef', () => {
|
||||||
|
@ -777,8 +768,10 @@ describe('ngtsc behavioral tests', () => {
|
||||||
|
|
||||||
env.driveMain();
|
env.driveMain();
|
||||||
const jsContents = env.getContents('test.js');
|
const jsContents = env.getContents('test.js');
|
||||||
expect(jsContents).toContain(`i0.ɵquery(TemplateRef, true)`);
|
// match `i0.ɵcontentQuery(dirIndex, TemplateRef, true)`
|
||||||
expect(jsContents).toContain(`i0.ɵquery(ViewContainerRef, true)`);
|
expect(jsContents).toMatch(contentQueryRegExp('TemplateRef', true));
|
||||||
|
// match `i0.ɵcontentQuery(dirIndex, ViewContainerRef, true)`
|
||||||
|
expect(jsContents).toMatch(contentQueryRegExp('ViewContainerRef', true));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate host listeners for components', () => {
|
it('should generate host listeners for components', () => {
|
||||||
|
|
|
@ -116,7 +116,6 @@ export class Identifiers {
|
||||||
static i18nPostprocess: o.ExternalReference = {name: 'ɵi18nPostprocess', moduleName: CORE};
|
static i18nPostprocess: o.ExternalReference = {name: 'ɵi18nPostprocess', moduleName: CORE};
|
||||||
|
|
||||||
static load: o.ExternalReference = {name: 'ɵload', moduleName: CORE};
|
static load: o.ExternalReference = {name: 'ɵload', moduleName: CORE};
|
||||||
static loadQueryList: o.ExternalReference = {name: 'ɵloadQueryList', moduleName: CORE};
|
|
||||||
|
|
||||||
static pipe: o.ExternalReference = {name: 'ɵpipe', moduleName: CORE};
|
static pipe: o.ExternalReference = {name: 'ɵpipe', moduleName: CORE};
|
||||||
|
|
||||||
|
@ -185,12 +184,11 @@ export class Identifiers {
|
||||||
|
|
||||||
static definePipe: o.ExternalReference = {name: 'ɵdefinePipe', moduleName: CORE};
|
static definePipe: o.ExternalReference = {name: 'ɵdefinePipe', moduleName: CORE};
|
||||||
|
|
||||||
static query: o.ExternalReference = {name: 'ɵquery', moduleName: CORE};
|
|
||||||
static queryRefresh: o.ExternalReference = {name: 'ɵqueryRefresh', moduleName: CORE};
|
static queryRefresh: o.ExternalReference = {name: 'ɵqueryRefresh', moduleName: CORE};
|
||||||
static viewQuery: o.ExternalReference = {name: 'ɵviewQuery', moduleName: CORE};
|
static viewQuery: o.ExternalReference = {name: 'ɵviewQuery', moduleName: CORE};
|
||||||
static loadViewQuery: o.ExternalReference = {name: 'ɵloadViewQuery', moduleName: CORE};
|
static loadViewQuery: o.ExternalReference = {name: 'ɵloadViewQuery', moduleName: CORE};
|
||||||
static registerContentQuery:
|
static contentQuery: o.ExternalReference = {name: 'ɵcontentQuery', moduleName: CORE};
|
||||||
o.ExternalReference = {name: 'ɵregisterContentQuery', moduleName: CORE};
|
static loadContentQuery: o.ExternalReference = {name: 'ɵloadContentQuery', moduleName: CORE};
|
||||||
|
|
||||||
static NgOnChangesFeature: o.ExternalReference = {name: 'ɵNgOnChangesFeature', moduleName: CORE};
|
static NgOnChangesFeature: o.ExternalReference = {name: 'ɵNgOnChangesFeature', moduleName: CORE};
|
||||||
|
|
||||||
|
|
|
@ -496,10 +496,6 @@ function prepareQueryParams(query: R3QueryMetadata, constantPool: ConstantPool):
|
||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createQueryDefinition(query: R3QueryMetadata, constantPool: ConstantPool): o.Expression {
|
|
||||||
return o.importExpr(R3.query).callFn(prepareQueryParams(query, constantPool));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turn a directive selector into an R3-compatible selector for directive def
|
// Turn a directive selector into an R3-compatible selector for directive def
|
||||||
function createDirectiveSelector(selector: string | null): o.Expression {
|
function createDirectiveSelector(selector: string | null): o.Expression {
|
||||||
return asLiteral(core.parseSelectorToR3Selector(selector));
|
return asLiteral(core.parseSelectorToR3Selector(selector));
|
||||||
|
@ -519,10 +515,8 @@ function createContentQueriesFunction(
|
||||||
meta: R3DirectiveMetadata, constantPool: ConstantPool): o.Expression|null {
|
meta: R3DirectiveMetadata, constantPool: ConstantPool): o.Expression|null {
|
||||||
if (meta.queries.length) {
|
if (meta.queries.length) {
|
||||||
const statements: o.Statement[] = meta.queries.map((query: R3QueryMetadata) => {
|
const statements: o.Statement[] = meta.queries.map((query: R3QueryMetadata) => {
|
||||||
const queryDefinition = createQueryDefinition(query, constantPool);
|
const args = [o.variable('dirIndex'), ...prepareQueryParams(query, constantPool) as any];
|
||||||
return o.importExpr(R3.registerContentQuery)
|
return o.importExpr(R3.contentQuery).callFn(args).toStmt();
|
||||||
.callFn([queryDefinition, o.variable('dirIndex')])
|
|
||||||
.toStmt();
|
|
||||||
});
|
});
|
||||||
const typeName = meta.name;
|
const typeName = meta.name;
|
||||||
const parameters = [new o.FnParam('dirIndex', o.NUMBER_TYPE)];
|
const parameters = [new o.FnParam('dirIndex', o.NUMBER_TYPE)];
|
||||||
|
@ -539,10 +533,7 @@ function createContentQueriesRefreshFunction(meta: R3DirectiveMetadata): o.Expre
|
||||||
if (meta.queries.length > 0) {
|
if (meta.queries.length > 0) {
|
||||||
const statements: o.Statement[] = [];
|
const statements: o.Statement[] = [];
|
||||||
const typeName = meta.name;
|
const typeName = meta.name;
|
||||||
const parameters = [
|
const parameters = [new o.FnParam('dirIndex', o.NUMBER_TYPE)];
|
||||||
new o.FnParam('dirIndex', o.NUMBER_TYPE),
|
|
||||||
new o.FnParam('queryStartIndex', o.NUMBER_TYPE),
|
|
||||||
];
|
|
||||||
const directiveInstanceVar = o.variable('instance');
|
const directiveInstanceVar = o.variable('instance');
|
||||||
// var $tmp$: any;
|
// var $tmp$: any;
|
||||||
const temporary = temporaryAllocator(statements, TEMPORARY_NAME);
|
const temporary = temporaryAllocator(statements, TEMPORARY_NAME);
|
||||||
|
@ -551,11 +542,8 @@ function createContentQueriesRefreshFunction(meta: R3DirectiveMetadata): o.Expre
|
||||||
statements.push(directiveInstanceVar.set(o.importExpr(R3.load).callFn([o.variable('dirIndex')]))
|
statements.push(directiveInstanceVar.set(o.importExpr(R3.load).callFn([o.variable('dirIndex')]))
|
||||||
.toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
.toDeclStmt(o.INFERRED_TYPE, [o.StmtModifier.Final]));
|
||||||
|
|
||||||
meta.queries.forEach((query: R3QueryMetadata, idx: number) => {
|
meta.queries.forEach((query: R3QueryMetadata) => {
|
||||||
const loadQLArg = o.variable('queryStartIndex');
|
const getQueryList = o.importExpr(R3.loadContentQuery).callFn([]);
|
||||||
const getQueryList = o.importExpr(R3.loadQueryList).callFn([
|
|
||||||
idx > 0 ? loadQLArg.plus(o.literal(idx)) : loadQLArg
|
|
||||||
]);
|
|
||||||
const assignToTemporary = temporary().set(getQueryList);
|
const assignToTemporary = temporary().set(getQueryList);
|
||||||
const callQueryRefresh = o.importExpr(R3.queryRefresh).callFn([assignToTemporary]);
|
const callQueryRefresh = o.importExpr(R3.queryRefresh).callFn([assignToTemporary]);
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,6 @@ export {
|
||||||
listener as ɵlistener,
|
listener as ɵlistener,
|
||||||
text as ɵtext,
|
text as ɵtext,
|
||||||
embeddedViewStart as ɵembeddedViewStart,
|
embeddedViewStart as ɵembeddedViewStart,
|
||||||
query as ɵquery,
|
|
||||||
registerContentQuery as ɵregisterContentQuery,
|
|
||||||
projection as ɵprojection,
|
projection as ɵprojection,
|
||||||
bind as ɵbind,
|
bind as ɵbind,
|
||||||
interpolation1 as ɵinterpolation1,
|
interpolation1 as ɵinterpolation1,
|
||||||
|
@ -84,7 +82,8 @@ export {
|
||||||
queryRefresh as ɵqueryRefresh,
|
queryRefresh as ɵqueryRefresh,
|
||||||
viewQuery as ɵviewQuery,
|
viewQuery as ɵviewQuery,
|
||||||
loadViewQuery as ɵloadViewQuery,
|
loadViewQuery as ɵloadViewQuery,
|
||||||
loadQueryList as ɵloadQueryList,
|
contentQuery as ɵcontentQuery,
|
||||||
|
loadContentQuery as ɵloadContentQuery,
|
||||||
elementEnd as ɵelementEnd,
|
elementEnd as ɵelementEnd,
|
||||||
elementProperty as ɵelementProperty,
|
elementProperty as ɵelementProperty,
|
||||||
componentHostSyntheticProperty as ɵcomponentHostSyntheticProperty,
|
componentHostSyntheticProperty as ɵcomponentHostSyntheticProperty,
|
||||||
|
|
|
@ -136,7 +136,7 @@ export function defineComponent<T>(componentDefinition: {
|
||||||
contentQueries?: ((dirIndex: number) => void);
|
contentQueries?: ((dirIndex: number) => void);
|
||||||
|
|
||||||
/** Refreshes content queries associated with directives in a given view */
|
/** Refreshes content queries associated with directives in a given view */
|
||||||
contentQueriesRefresh?: ((directiveIndex: number, queryIndex: number) => void);
|
contentQueriesRefresh?: ((directiveIndex: number) => void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the name that can be used in the template to assign this directive to a variable.
|
* Defines the name that can be used in the template to assign this directive to a variable.
|
||||||
|
|
|
@ -103,9 +103,9 @@ export function InheritDefinitionFeature(definition: DirectiveDef<any>| Componen
|
||||||
const superContentQueries = superDef.contentQueries;
|
const superContentQueries = superDef.contentQueries;
|
||||||
if (superContentQueries) {
|
if (superContentQueries) {
|
||||||
if (prevContentQueries) {
|
if (prevContentQueries) {
|
||||||
definition.contentQueries = (dirIndex: number) => {
|
definition.contentQueries = (directiveIndex: number) => {
|
||||||
superContentQueries(dirIndex);
|
superContentQueries(directiveIndex);
|
||||||
prevContentQueries(dirIndex);
|
prevContentQueries(directiveIndex);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
definition.contentQueries = superContentQueries;
|
definition.contentQueries = superContentQueries;
|
||||||
|
@ -117,9 +117,9 @@ export function InheritDefinitionFeature(definition: DirectiveDef<any>| Componen
|
||||||
const superContentQueriesRefresh = superDef.contentQueriesRefresh;
|
const superContentQueriesRefresh = superDef.contentQueriesRefresh;
|
||||||
if (superContentQueriesRefresh) {
|
if (superContentQueriesRefresh) {
|
||||||
if (prevContentQueriesRefresh) {
|
if (prevContentQueriesRefresh) {
|
||||||
definition.contentQueriesRefresh = (directiveIndex: number, queryIndex: number) => {
|
definition.contentQueriesRefresh = (directiveIndex: number) => {
|
||||||
superContentQueriesRefresh(directiveIndex, queryIndex);
|
superContentQueriesRefresh(directiveIndex);
|
||||||
prevContentQueriesRefresh(directiveIndex, queryIndex);
|
prevContentQueriesRefresh(directiveIndex);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
definition.contentQueriesRefresh = superContentQueriesRefresh;
|
definition.contentQueriesRefresh = superContentQueriesRefresh;
|
||||||
|
|
|
@ -122,15 +122,12 @@ export {
|
||||||
} from './pipe';
|
} from './pipe';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
query,
|
|
||||||
queryRefresh,
|
queryRefresh,
|
||||||
viewQuery,
|
viewQuery,
|
||||||
loadViewQuery,
|
loadViewQuery,
|
||||||
|
contentQuery,
|
||||||
|
loadContentQuery,
|
||||||
} from './query';
|
} from './query';
|
||||||
export {
|
|
||||||
registerContentQuery,
|
|
||||||
loadQueryList,
|
|
||||||
} from './instructions';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
pureFunction0,
|
pureFunction0,
|
||||||
|
|
|
@ -36,7 +36,7 @@ import {BINDING_INDEX, CLEANUP, CONTAINER_INDEX, CONTENT_QUERIES, CONTEXT, DECLA
|
||||||
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
|
||||||
import {appendChild, appendProjectedNode, createTextNode, getLViewChild, insertView, removeView} from './node_manipulation';
|
import {appendChild, appendProjectedNode, createTextNode, getLViewChild, insertView, removeView} from './node_manipulation';
|
||||||
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector_matcher';
|
||||||
import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCurrentDirectiveDef, getCurrentViewQueryIndex, getElementDepthCount, getFirstTemplatePass, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, isCreationMode, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentViewQueryIndex, setFirstTemplatePass, setIsParent, setPreviousOrParentTNode} from './state';
|
import {decreaseElementDepthCount, enterView, getBindingsEnabled, getCheckNoChangesMode, getContextLView, getCurrentDirectiveDef, getCurrentQueryIndex, getElementDepthCount, getFirstTemplatePass, getIsParent, getLView, getPreviousOrParentTNode, increaseElementDepthCount, isCreationMode, leaveView, nextContextImpl, resetComponentState, setBindingRoot, setCheckNoChangesMode, setCurrentDirectiveDef, setCurrentQueryIndex, setFirstTemplatePass, setIsParent, setPreviousOrParentTNode} from './state';
|
||||||
import {getInitialClassNameValue, initializeStaticContext as initializeStaticStylingContext, patchContextWithStaticAttrs, renderInitialStylesAndClasses, renderStyling, updateClassProp as updateElementClassProp, updateContextWithBindings, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings';
|
import {getInitialClassNameValue, initializeStaticContext as initializeStaticStylingContext, patchContextWithStaticAttrs, renderInitialStylesAndClasses, renderStyling, updateClassProp as updateElementClassProp, updateContextWithBindings, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling/class_and_style_bindings';
|
||||||
import {BoundPlayerFactory} from './styling/player_factory';
|
import {BoundPlayerFactory} from './styling/player_factory';
|
||||||
import {createEmptyStylingContext, getStylingContext, hasClassInput, hasStyling, isAnimationProp} from './styling/util';
|
import {createEmptyStylingContext, getStylingContext, hasClassInput, hasStyling, isAnimationProp} from './styling/util';
|
||||||
|
@ -137,12 +137,11 @@ export function setHostBindings(tView: TView, viewData: LView): void {
|
||||||
/** Refreshes content queries for all directives in the given view. */
|
/** Refreshes content queries for all directives in the given view. */
|
||||||
function refreshContentQueries(tView: TView): void {
|
function refreshContentQueries(tView: TView): void {
|
||||||
if (tView.contentQueries != null) {
|
if (tView.contentQueries != null) {
|
||||||
for (let i = 0; i < tView.contentQueries.length; i += 2) {
|
setCurrentQueryIndex(0);
|
||||||
|
for (let i = 0; i < tView.contentQueries.length; i++) {
|
||||||
const directiveDefIdx = tView.contentQueries[i];
|
const directiveDefIdx = tView.contentQueries[i];
|
||||||
const directiveDef = tView.data[directiveDefIdx] as DirectiveDef<any>;
|
const directiveDef = tView.data[directiveDefIdx] as DirectiveDef<any>;
|
||||||
|
directiveDef.contentQueriesRefresh !(directiveDefIdx - HEADER_OFFSET);
|
||||||
directiveDef.contentQueriesRefresh !(
|
|
||||||
directiveDefIdx - HEADER_OFFSET, tView.contentQueries[i + 1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2762,7 +2761,7 @@ export function checkView<T>(hostView: LView, component: T) {
|
||||||
function executeViewQueryFn<T>(lView: LView, tView: TView, component: T): void {
|
function executeViewQueryFn<T>(lView: LView, tView: TView, component: T): void {
|
||||||
const viewQuery = tView.viewQuery;
|
const viewQuery = tView.viewQuery;
|
||||||
if (viewQuery) {
|
if (viewQuery) {
|
||||||
setCurrentViewQueryIndex(tView.viewQueryStartIndex);
|
setCurrentQueryIndex(tView.viewQueryStartIndex);
|
||||||
viewQuery(getRenderFlags(lView), component);
|
viewQuery(getRenderFlags(lView), component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3111,16 +3110,6 @@ export function reference<T>(index: number) {
|
||||||
return loadInternal<T>(contextLView, index);
|
return loadInternal<T>(contextLView, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadQueryList<T>(queryListIdx: number): QueryList<T> {
|
|
||||||
const lView = getLView();
|
|
||||||
ngDevMode &&
|
|
||||||
assertDefined(
|
|
||||||
lView[CONTENT_QUERIES], 'Content QueryList array should be defined if reading a query.');
|
|
||||||
ngDevMode && assertDataInRange(lView[CONTENT_QUERIES] !, queryListIdx);
|
|
||||||
|
|
||||||
return lView[CONTENT_QUERIES] ![queryListIdx];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Retrieves a value from current `viewData`. */
|
/** Retrieves a value from current `viewData`. */
|
||||||
export function load<T>(index: number): T {
|
export function load<T>(index: number): T {
|
||||||
return loadInternal<T>(getLView(), index);
|
return loadInternal<T>(getLView(), index);
|
||||||
|
@ -3170,26 +3159,6 @@ export function injectAttribute(attrNameToInject: string): string|null {
|
||||||
return injectAttributeImpl(getPreviousOrParentTNode(), attrNameToInject);
|
return injectAttributeImpl(getPreviousOrParentTNode(), attrNameToInject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a QueryList, associated with a content query, for later refresh (part of a view
|
|
||||||
* refresh).
|
|
||||||
*/
|
|
||||||
export function registerContentQuery<Q>(
|
|
||||||
queryList: QueryList<Q>, currentDirectiveIndex: number): void {
|
|
||||||
const viewData = getLView();
|
|
||||||
const tView = viewData[TVIEW];
|
|
||||||
const savedContentQueriesLength =
|
|
||||||
(viewData[CONTENT_QUERIES] || (viewData[CONTENT_QUERIES] = [])).push(queryList);
|
|
||||||
if (getFirstTemplatePass()) {
|
|
||||||
const tViewContentQueries = tView.contentQueries || (tView.contentQueries = []);
|
|
||||||
const lastSavedDirectiveIndex =
|
|
||||||
tView.contentQueries.length ? tView.contentQueries[tView.contentQueries.length - 2] : -1;
|
|
||||||
if (currentDirectiveIndex !== lastSavedDirectiveIndex) {
|
|
||||||
tViewContentQueries.push(currentDirectiveIndex, savedContentQueriesLength - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CLEAN_PROMISE = _CLEAN_PROMISE;
|
export const CLEAN_PROMISE = _CLEAN_PROMISE;
|
||||||
|
|
||||||
function initializeTNodeInputs(tNode: TNode | null): PropertyAliases|null {
|
function initializeTNodeInputs(tNode: TNode | null): PropertyAliases|null {
|
||||||
|
|
|
@ -134,7 +134,7 @@ export interface DirectiveDef<T> extends BaseDef<T> {
|
||||||
contentQueries: ((directiveIndex: number) => void)|null;
|
contentQueries: ((directiveIndex: number) => void)|null;
|
||||||
|
|
||||||
/** Refreshes content queries associated with directives in a given view */
|
/** Refreshes content queries associated with directives in a given view */
|
||||||
contentQueriesRefresh: ((directiveIndex: number, queryIndex: number) => void)|null;
|
contentQueriesRefresh: ((directiveIndex: number) => void)|null;
|
||||||
|
|
||||||
/** Refreshes host bindings on the associated directive. */
|
/** Refreshes host bindings on the associated directive. */
|
||||||
hostBindings: HostBindingsFunction<T>|null;
|
hostBindings: HostBindingsFunction<T>|null;
|
||||||
|
|
|
@ -509,9 +509,6 @@ export interface TView {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of indices for child directives that have content queries.
|
* A list of indices for child directives that have content queries.
|
||||||
*
|
|
||||||
* Even indices: Directive indices
|
|
||||||
* Odd indices: Starting index of content queries (stored in CONTENT_QUERIES) for this directive
|
|
||||||
*/
|
*/
|
||||||
contentQueries: number[]|null;
|
contentQueries: number[]|null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
||||||
'ɵnextContext': r3.nextContext,
|
'ɵnextContext': r3.nextContext,
|
||||||
'ɵcontainerRefreshStart': r3.containerRefreshStart,
|
'ɵcontainerRefreshStart': r3.containerRefreshStart,
|
||||||
'ɵcontainerRefreshEnd': r3.containerRefreshEnd,
|
'ɵcontainerRefreshEnd': r3.containerRefreshEnd,
|
||||||
'ɵloadQueryList': r3.loadQueryList,
|
|
||||||
'ɵnamespaceHTML': r3.namespaceHTML,
|
'ɵnamespaceHTML': r3.namespaceHTML,
|
||||||
'ɵnamespaceMathML': r3.namespaceMathML,
|
'ɵnamespaceMathML': r3.namespaceMathML,
|
||||||
'ɵnamespaceSVG': r3.namespaceSVG,
|
'ɵnamespaceSVG': r3.namespaceSVG,
|
||||||
|
@ -87,11 +86,11 @@ export const angularCoreEnv: {[name: string]: Function} = {
|
||||||
'ɵpipeBindV': r3.pipeBindV,
|
'ɵpipeBindV': r3.pipeBindV,
|
||||||
'ɵprojectionDef': r3.projectionDef,
|
'ɵprojectionDef': r3.projectionDef,
|
||||||
'ɵpipe': r3.pipe,
|
'ɵpipe': r3.pipe,
|
||||||
'ɵquery': r3.query,
|
|
||||||
'ɵqueryRefresh': r3.queryRefresh,
|
'ɵqueryRefresh': r3.queryRefresh,
|
||||||
'ɵviewQuery': r3.viewQuery,
|
'ɵviewQuery': r3.viewQuery,
|
||||||
'ɵloadViewQuery': r3.loadViewQuery,
|
'ɵloadViewQuery': r3.loadViewQuery,
|
||||||
'ɵregisterContentQuery': r3.registerContentQuery,
|
'ɵcontentQuery': r3.contentQuery,
|
||||||
|
'ɵloadContentQuery': r3.loadContentQuery,
|
||||||
'ɵreference': r3.reference,
|
'ɵreference': r3.reference,
|
||||||
'ɵelementStyling': r3.elementStyling,
|
'ɵelementStyling': r3.elementStyling,
|
||||||
'ɵelementHostAttrs': r3.elementHostAttrs,
|
'ɵelementHostAttrs': r3.elementHostAttrs,
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {Type} from '../interface/type';
|
||||||
import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
|
import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
|
||||||
import {QueryList} from '../linker/query_list';
|
import {QueryList} from '../linker/query_list';
|
||||||
import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
|
import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
|
||||||
import {assertDefined, assertEqual} from '../util/assert';
|
import {assertDataInRange, assertDefined, assertEqual} from '../util/assert';
|
||||||
|
|
||||||
import {assertPreviousIsParent} from './assert';
|
import {assertPreviousIsParent} from './assert';
|
||||||
import {getNodeInjectable, locateDirectiveOrProvider} from './di';
|
import {getNodeInjectable, locateDirectiveOrProvider} from './di';
|
||||||
|
@ -23,8 +23,8 @@ import {unusedValueExportToPlacateAjd as unused1} from './interfaces/definition'
|
||||||
import {unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
|
import {unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
|
||||||
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
|
import {TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeType, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
|
||||||
import {LQueries, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
|
import {LQueries, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
|
||||||
import {HEADER_OFFSET, LView, TVIEW} from './interfaces/view';
|
import {CONTENT_QUERIES, HEADER_OFFSET, LView, TVIEW} from './interfaces/view';
|
||||||
import {getCurrentViewQueryIndex, getIsParent, getLView, getOrCreateCurrentQueries, setCurrentViewQueryIndex} from './state';
|
import {getCurrentQueryIndex, getFirstTemplatePass, getIsParent, getLView, getOrCreateCurrentQueries, setCurrentQueryIndex} from './state';
|
||||||
import {isContentQueryHost} from './util';
|
import {isContentQueryHost} from './util';
|
||||||
import {createElementRef, createTemplateRef} from './view_engine_compatibility';
|
import {createElementRef, createTemplateRef} from './view_engine_compatibility';
|
||||||
|
|
||||||
|
@ -405,10 +405,10 @@ export function viewQuery<T>(
|
||||||
if (tView.firstTemplatePass) {
|
if (tView.firstTemplatePass) {
|
||||||
tView.expandoStartIndex++;
|
tView.expandoStartIndex++;
|
||||||
}
|
}
|
||||||
const index = getCurrentViewQueryIndex();
|
const index = getCurrentQueryIndex();
|
||||||
const viewQuery: QueryList<T> = query<T>(predicate, descend, read);
|
const viewQuery: QueryList<T> = query<T>(predicate, descend, read);
|
||||||
store(index - HEADER_OFFSET, viewQuery);
|
store(index - HEADER_OFFSET, viewQuery);
|
||||||
setCurrentViewQueryIndex(index + 1);
|
setCurrentQueryIndex(index + 1);
|
||||||
return viewQuery;
|
return viewQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -416,7 +416,49 @@ export function viewQuery<T>(
|
||||||
* Loads current View Query and moves the pointer/index to the next View Query in LView.
|
* Loads current View Query and moves the pointer/index to the next View Query in LView.
|
||||||
*/
|
*/
|
||||||
export function loadViewQuery<T>(): T {
|
export function loadViewQuery<T>(): T {
|
||||||
const index = getCurrentViewQueryIndex();
|
const index = getCurrentQueryIndex();
|
||||||
setCurrentViewQueryIndex(index + 1);
|
setCurrentQueryIndex(index + 1);
|
||||||
return load<T>(index - HEADER_OFFSET);
|
return load<T>(index - HEADER_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a QueryList, associated with a content query, for later refresh (part of a view
|
||||||
|
* refresh).
|
||||||
|
*
|
||||||
|
* @param directiveIndex Current directive index
|
||||||
|
* @param predicate The type for which the query will search
|
||||||
|
* @param descend Whether or not to descend into children
|
||||||
|
* @param read What to save in the query
|
||||||
|
* @returns QueryList<T>
|
||||||
|
*/
|
||||||
|
export function contentQuery<T>(
|
||||||
|
directiveIndex: number, predicate: Type<any>| string[], descend?: boolean,
|
||||||
|
// TODO: "read" should be an AbstractType (FW-486)
|
||||||
|
read?: any): QueryList<T> {
|
||||||
|
const lView = getLView();
|
||||||
|
const tView = lView[TVIEW];
|
||||||
|
const contentQuery: QueryList<T> = query<T>(predicate, descend, read);
|
||||||
|
(lView[CONTENT_QUERIES] || (lView[CONTENT_QUERIES] = [])).push(contentQuery);
|
||||||
|
if (getFirstTemplatePass()) {
|
||||||
|
const tViewContentQueries = tView.contentQueries || (tView.contentQueries = []);
|
||||||
|
const lastSavedDirectiveIndex =
|
||||||
|
tView.contentQueries.length ? tView.contentQueries[tView.contentQueries.length - 1] : -1;
|
||||||
|
if (directiveIndex !== lastSavedDirectiveIndex) {
|
||||||
|
tViewContentQueries.push(directiveIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return contentQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadContentQuery<T>(): QueryList<T> {
|
||||||
|
const lView = getLView();
|
||||||
|
ngDevMode &&
|
||||||
|
assertDefined(
|
||||||
|
lView[CONTENT_QUERIES], 'Content QueryList array should be defined if reading a query.');
|
||||||
|
|
||||||
|
const index = getCurrentQueryIndex();
|
||||||
|
ngDevMode && assertDataInRange(lView[CONTENT_QUERIES] !, index);
|
||||||
|
|
||||||
|
setCurrentQueryIndex(index + 1);
|
||||||
|
return lView[CONTENT_QUERIES] ![index];
|
||||||
|
}
|
|
@ -257,18 +257,18 @@ export function setBindingRoot(value: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current index of a View Query which needs to be processed next.
|
* Current index of a View or Content Query which needs to be processed next.
|
||||||
* We iterate over the list of View Queries stored in LView and increment current query index.
|
* We iterate over the list of Queries and increment current query index at every step.
|
||||||
*/
|
*/
|
||||||
let viewQueryIndex: number = 0;
|
let currentQueryIndex: number = 0;
|
||||||
|
|
||||||
export function getCurrentViewQueryIndex(): number {
|
export function getCurrentQueryIndex(): number {
|
||||||
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
|
// top level variables should not be exported for performance reasons (PERF_NOTES.md)
|
||||||
return viewQueryIndex;
|
return currentQueryIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setCurrentViewQueryIndex(value: number): void {
|
export function setCurrentQueryIndex(value: number): void {
|
||||||
viewQueryIndex = value;
|
currentQueryIndex = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -408,7 +408,7 @@
|
||||||
"name": "setCurrentDirectiveDef"
|
"name": "setCurrentDirectiveDef"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setCurrentViewQueryIndex"
|
"name": "setCurrentQueryIndex"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setFirstTemplatePass"
|
"name": "setFirstTemplatePass"
|
||||||
|
|
|
@ -1134,7 +1134,7 @@
|
||||||
"name": "setCurrentDirectiveDef"
|
"name": "setCurrentDirectiveDef"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setCurrentViewQueryIndex"
|
"name": "setCurrentQueryIndex"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "setDirectiveDirty"
|
"name": "setDirectiveDirty"
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
import {ElementRef, QueryList, ViewContainerRef} from '@angular/core';
|
import {ElementRef, QueryList, ViewContainerRef} from '@angular/core';
|
||||||
|
|
||||||
import {AttributeMarker, defineComponent, template, defineDirective, InheritDefinitionFeature, ProvidersFeature, NgOnChangesFeature} from '../../src/render3/index';
|
import {AttributeMarker, defineComponent, template, defineDirective, InheritDefinitionFeature, ProvidersFeature, NgOnChangesFeature} from '../../src/render3/index';
|
||||||
import {allocHostVars, bind, directiveInject, element, elementAttribute, elementEnd, elementProperty, elementStyleProp, elementStyling, elementStylingApply, elementStart, listener, load, text, textBinding, loadQueryList, registerContentQuery, elementHostAttrs} from '../../src/render3/instructions';
|
import {allocHostVars, bind, directiveInject, element, elementAttribute, elementEnd, elementProperty, elementStyleProp, elementStyling, elementStylingApply, elementStart, listener, load, text, textBinding, elementHostAttrs} from '../../src/render3/instructions';
|
||||||
import {query, queryRefresh} from '../../src/render3/query';
|
import {loadContentQuery, contentQuery, queryRefresh} from '../../src/render3/query';
|
||||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
import {pureFunction1, pureFunction2} from '../../src/render3/pure_function';
|
import {pureFunction1, pureFunction2} from '../../src/render3/pure_function';
|
||||||
import {sanitizeUrl, sanitizeUrlOrResourceUrl, sanitizeHtml} from '../../src/sanitization/sanitization';
|
import {sanitizeUrl, sanitizeUrlOrResourceUrl, sanitizeHtml} from '../../src/sanitization/sanitization';
|
||||||
|
@ -1009,11 +1009,11 @@ describe('host bindings', () => {
|
||||||
elementProperty(elIndex, 'id', bind(ctx.foos.length), null, true);
|
elementProperty(elIndex, 'id', bind(ctx.foos.length), null, true);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
contentQueries: (dirIndex) => { registerContentQuery(query(['foo']), dirIndex); },
|
contentQueries: (dirIndex: number) => { contentQuery(dirIndex, ['foo']); },
|
||||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
contentQueriesRefresh: (dirIndex: number) => {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
const instance = load<HostBindingWithContentChildren>(dirIndex);
|
const instance = load<HostBindingWithContentChildren>(dirIndex);
|
||||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) && (instance.foos = tmp);
|
queryRefresh(tmp = loadContentQuery<ElementRef>()) && (instance.foos = tmp);
|
||||||
},
|
},
|
||||||
template: (rf: RenderFlags, cmp: HostBindingWithContentChildren) => {}
|
template: (rf: RenderFlags, cmp: HostBindingWithContentChildren) => {}
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Inject, InjectionToken, QueryList} from '../../src/core';
|
import {ElementRef, Inject, InjectionToken, QueryList, ɵAttributeMarker as AttributeMarker} from '../../src/core';
|
||||||
import {ComponentDef, DirectiveDef, InheritDefinitionFeature, NgOnChangesFeature, ProvidersFeature, RenderFlags, allocHostVars, bind, defineBase, defineComponent, defineDirective, directiveInject, element, elementProperty, loadViewQuery, queryRefresh, viewQuery} from '../../src/render3/index';
|
import {ComponentDef, DirectiveDef, InheritDefinitionFeature, NgOnChangesFeature, ProvidersFeature, RenderFlags, allocHostVars, bind, contentQuery, defineBase, defineComponent, defineDirective, directiveInject, element, elementEnd, elementProperty, elementStart, load, loadContentQuery, loadViewQuery, queryRefresh, viewQuery} from '../../src/render3/index';
|
||||||
|
|
||||||
import {ComponentFixture, createComponent, getDirectiveOnNode} from './render_util';
|
import {ComponentFixture, createComponent, getDirectiveOnNode} from './render_util';
|
||||||
|
|
||||||
|
@ -549,14 +549,14 @@ describe('InheritDefinitionFeature', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should compose contentQueriesRefresh', () => {
|
it('should compose contentQueriesRefresh', () => {
|
||||||
const log: Array<[string, number, number]> = [];
|
const log: Array<[string, number]> = [];
|
||||||
|
|
||||||
class SuperDirective {
|
class SuperDirective {
|
||||||
static ngDirectiveDef = defineDirective({
|
static ngDirectiveDef = defineDirective({
|
||||||
type: SuperDirective,
|
type: SuperDirective,
|
||||||
selectors: [['', 'superDir', '']],
|
selectors: [['', 'superDir', '']],
|
||||||
contentQueriesRefresh: (directiveIndex: number, queryIndex: number) => {
|
contentQueriesRefresh: (directiveIndex: number) => {
|
||||||
log.push(['super', directiveIndex, queryIndex]);
|
log.push(['super', directiveIndex]);
|
||||||
},
|
},
|
||||||
factory: () => new SuperDirective(),
|
factory: () => new SuperDirective(),
|
||||||
});
|
});
|
||||||
|
@ -566,8 +566,8 @@ describe('InheritDefinitionFeature', () => {
|
||||||
static ngDirectiveDef = defineDirective({
|
static ngDirectiveDef = defineDirective({
|
||||||
type: SubDirective,
|
type: SubDirective,
|
||||||
selectors: [['', 'subDir', '']],
|
selectors: [['', 'subDir', '']],
|
||||||
contentQueriesRefresh: (directiveIndex: number, queryIndex: number) => {
|
contentQueriesRefresh: (directiveIndex: number) => {
|
||||||
log.push(['sub', directiveIndex, queryIndex]);
|
log.push(['sub', directiveIndex]);
|
||||||
},
|
},
|
||||||
factory: () => new SubDirective(),
|
factory: () => new SubDirective(),
|
||||||
features: [InheritDefinitionFeature]
|
features: [InheritDefinitionFeature]
|
||||||
|
@ -576,9 +576,68 @@ describe('InheritDefinitionFeature', () => {
|
||||||
|
|
||||||
const subDef = SubDirective.ngDirectiveDef as DirectiveDef<any>;
|
const subDef = SubDirective.ngDirectiveDef as DirectiveDef<any>;
|
||||||
|
|
||||||
subDef.contentQueriesRefresh !(1, 2);
|
subDef.contentQueriesRefresh !(1);
|
||||||
|
|
||||||
expect(log).toEqual([['super', 1, 2], ['sub', 1, 2]]);
|
expect(log).toEqual([['super', 1], ['sub', 1]]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should compose contentQueries and contentQueriesRefresh', () => {
|
||||||
|
let dirInstance: SubDirective;
|
||||||
|
class SuperDirective {
|
||||||
|
// @ContentChildren('foo')
|
||||||
|
foos !: QueryList<ElementRef>;
|
||||||
|
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: SuperDirective,
|
||||||
|
selectors: [['', 'super-dir', '']],
|
||||||
|
factory: () => new SuperDirective(),
|
||||||
|
contentQueries: (dirIndex: number) => { contentQuery(dirIndex, ['foo'], true); },
|
||||||
|
contentQueriesRefresh: (dirIndex: number) => {
|
||||||
|
let tmp: any;
|
||||||
|
const instance = load<SuperDirective>(dirIndex);
|
||||||
|
queryRefresh(tmp = loadContentQuery<ElementRef>()) && (instance.foos = tmp);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubDirective extends SuperDirective {
|
||||||
|
// @ContentChildren('bar')
|
||||||
|
bars !: QueryList<ElementRef>;
|
||||||
|
|
||||||
|
static ngDirectiveDef = defineDirective({
|
||||||
|
type: SubDirective,
|
||||||
|
selectors: [['', 'sub-dir', '']],
|
||||||
|
factory: () => new SubDirective(),
|
||||||
|
contentQueries: (dirIndex: number) => { contentQuery(dirIndex, ['bar'], true); },
|
||||||
|
contentQueriesRefresh: (dirIndex: number) => {
|
||||||
|
let tmp: any;
|
||||||
|
dirInstance = load<SubDirective>(dirIndex);
|
||||||
|
queryRefresh(tmp = loadContentQuery<ElementRef>()) && (dirInstance.bars = tmp);
|
||||||
|
},
|
||||||
|
features: [InheritDefinitionFeature]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <div sub-dir>
|
||||||
|
* <span #foo></span>
|
||||||
|
* <span #bar></span>
|
||||||
|
* </div>
|
||||||
|
*/
|
||||||
|
const AppComponent = createComponent('app-component', function(rf: RenderFlags, ctx: any) {
|
||||||
|
if (rf & RenderFlags.Create) {
|
||||||
|
elementStart(0, 'div', [AttributeMarker.SelectOnly, 'sub-dir']);
|
||||||
|
{
|
||||||
|
element(1, 'span', null, ['foo', '']);
|
||||||
|
element(3, 'span', null, ['bar', '']);
|
||||||
|
}
|
||||||
|
elementEnd();
|
||||||
|
}
|
||||||
|
}, 5, 0, [SubDirective]);
|
||||||
|
|
||||||
|
const fixture = new ComponentFixture(AppComponent);
|
||||||
|
expect(dirInstance !.foos.length).toBe(1);
|
||||||
|
expect(dirInstance !.bars.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw if inheriting a component from a directive', () => {
|
it('should throw if inheriting a component from a directive', () => {
|
||||||
|
|
|
@ -13,9 +13,9 @@ import {EventEmitter} from '../..';
|
||||||
import {AttributeMarker, ProvidersFeature, defineComponent, defineDirective, detectChanges} from '../../src/render3/index';
|
import {AttributeMarker, ProvidersFeature, defineComponent, defineDirective, detectChanges} from '../../src/render3/index';
|
||||||
import {getNativeByIndex} from '../../src/render3/util';
|
import {getNativeByIndex} from '../../src/render3/util';
|
||||||
|
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadQueryList, reference, registerContentQuery, template, text} from '../../src/render3/instructions';
|
import {bind, container, containerRefreshEnd, containerRefreshStart, directiveInject, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, reference, template, text} from '../../src/render3/instructions';
|
||||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
import {query, queryRefresh, viewQuery, loadViewQuery} from '../../src/render3/query';
|
import {queryRefresh, viewQuery, loadViewQuery, contentQuery, loadContentQuery} from '../../src/render3/query';
|
||||||
import {getLView} from '../../src/render3/state';
|
import {getLView} from '../../src/render3/state';
|
||||||
import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound';
|
import {templateRefExtractor} from '../../src/render3/view_engine_compatibility_prebound';
|
||||||
|
|
||||||
|
@ -2282,12 +2282,11 @@ describe('query', () => {
|
||||||
type: WithContentDirective,
|
type: WithContentDirective,
|
||||||
selectors: [['', 'with-content', '']],
|
selectors: [['', 'with-content', '']],
|
||||||
factory: () => new WithContentDirective(),
|
factory: () => new WithContentDirective(),
|
||||||
contentQueries: (dirIndex) => { registerContentQuery(query(['foo'], true), dirIndex); },
|
contentQueries: (dirIndex: number) => { contentQuery(dirIndex, ['foo'], true); },
|
||||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
contentQueriesRefresh: (dirIndex: number) => {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
withContentInstance = load<WithContentDirective>(dirIndex);
|
withContentInstance = load<WithContentDirective>(dirIndex);
|
||||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
queryRefresh(tmp = loadContentQuery<ElementRef>()) && (withContentInstance.foos = tmp);
|
||||||
(withContentInstance.foos = tmp);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2303,12 +2302,11 @@ describe('query', () => {
|
||||||
template: function(rf: RenderFlags, ctx: any) {},
|
template: function(rf: RenderFlags, ctx: any) {},
|
||||||
consts: 0,
|
consts: 0,
|
||||||
vars: 0,
|
vars: 0,
|
||||||
contentQueries: (dirIndex) => { registerContentQuery(query(['foo'], false), dirIndex); },
|
contentQueries: (dirIndex: number) => { contentQuery(dirIndex, ['foo'], false); },
|
||||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
contentQueriesRefresh: (dirIndex: number) => {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
shallowCompInstance = load<ShallowComp>(dirIndex);
|
shallowCompInstance = load<ShallowComp>(dirIndex);
|
||||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
queryRefresh(tmp = loadContentQuery<ElementRef>()) && (shallowCompInstance.foos = tmp);
|
||||||
(shallowCompInstance.foos = tmp);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2527,16 +2525,15 @@ describe('query', () => {
|
||||||
selectors: [['', 'query', '']],
|
selectors: [['', 'query', '']],
|
||||||
exportAs: ['query'],
|
exportAs: ['query'],
|
||||||
factory: () => new QueryDirective(),
|
factory: () => new QueryDirective(),
|
||||||
contentQueries: (dirIndex) => {
|
contentQueries: (dirIndex: number) => {
|
||||||
// @ContentChildren('foo, bar, baz', {descendants: true}) fooBars:
|
// @ContentChildren('foo, bar, baz', {descendants: true}) fooBars:
|
||||||
// QueryList<ElementRef>;
|
// QueryList<ElementRef>;
|
||||||
registerContentQuery(query(['foo', 'bar', 'baz'], true), dirIndex);
|
contentQuery(dirIndex, ['foo', 'bar', 'baz'], true);
|
||||||
},
|
},
|
||||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
contentQueriesRefresh: (dirIndex: number) => {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
const instance = load<QueryDirective>(dirIndex);
|
const instance = load<QueryDirective>(dirIndex);
|
||||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
queryRefresh(tmp = loadContentQuery<ElementRef>()) && (instance.fooBars = tmp);
|
||||||
(instance.fooBars = tmp);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2591,16 +2588,15 @@ describe('query', () => {
|
||||||
selectors: [['', 'query', '']],
|
selectors: [['', 'query', '']],
|
||||||
exportAs: ['query'],
|
exportAs: ['query'],
|
||||||
factory: () => new QueryDirective(),
|
factory: () => new QueryDirective(),
|
||||||
contentQueries: (dirIndex) => {
|
contentQueries: (dirIndex: number) => {
|
||||||
// @ContentChildren('foo, bar, baz', {descendants: true}) fooBars:
|
// @ContentChildren('foo, bar, baz', {descendants: true}) fooBars:
|
||||||
// QueryList<ElementRef>;
|
// QueryList<ElementRef>;
|
||||||
registerContentQuery(query(['foo'], false), dirIndex);
|
contentQuery(dirIndex, ['foo'], false);
|
||||||
},
|
},
|
||||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
contentQueriesRefresh: (dirIndex: number) => {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
const instance = load<QueryDirective>(dirIndex);
|
const instance = load<QueryDirective>(dirIndex);
|
||||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
queryRefresh(tmp = loadContentQuery<ElementRef>()) && (instance.fooBars = tmp);
|
||||||
(instance.fooBars = tmp);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2647,16 +2643,15 @@ describe('query', () => {
|
||||||
selectors: [['', 'query', '']],
|
selectors: [['', 'query', '']],
|
||||||
exportAs: ['query'],
|
exportAs: ['query'],
|
||||||
factory: () => new QueryDirective(),
|
factory: () => new QueryDirective(),
|
||||||
contentQueries: (dirIndex) => {
|
contentQueries: (dirIndex: number) => {
|
||||||
// @ContentChildren('foo', {descendants: true}) fooBars:
|
// @ContentChildren('foo', {descendants: true}) fooBars:
|
||||||
// QueryList<ElementRef>;
|
// QueryList<ElementRef>;
|
||||||
registerContentQuery(query(['foo'], false), dirIndex);
|
contentQuery(dirIndex, ['foo'], false);
|
||||||
},
|
},
|
||||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
contentQueriesRefresh: (dirIndex: number) => {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
const instance = load<QueryDirective>(dirIndex);
|
const instance = load<QueryDirective>(dirIndex);
|
||||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
queryRefresh(tmp = loadContentQuery<ElementRef>()) && (instance.fooBars = tmp);
|
||||||
(instance.fooBars = tmp);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2703,15 +2698,14 @@ describe('query', () => {
|
||||||
selectors: [['', 'shallow-query', '']],
|
selectors: [['', 'shallow-query', '']],
|
||||||
exportAs: ['shallow-query'],
|
exportAs: ['shallow-query'],
|
||||||
factory: () => new ShallowQueryDirective(),
|
factory: () => new ShallowQueryDirective(),
|
||||||
contentQueries: (dirIndex) => {
|
contentQueries: (dirIndex: number) => {
|
||||||
// @ContentChildren('foo', {descendants: false}) foos: QueryList<ElementRef>;
|
// @ContentChildren('foo', {descendants: false}) foos: QueryList<ElementRef>;
|
||||||
registerContentQuery(query(['foo'], false), dirIndex);
|
contentQuery(dirIndex, ['foo'], false);
|
||||||
},
|
},
|
||||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
contentQueriesRefresh: (dirIndex: number) => {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
const instance = load<ShallowQueryDirective>(dirIndex);
|
const instance = load<ShallowQueryDirective>(dirIndex);
|
||||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
queryRefresh(tmp = loadContentQuery<ElementRef>()) && (instance.foos = tmp);
|
||||||
(instance.foos = tmp);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2723,15 +2717,14 @@ describe('query', () => {
|
||||||
selectors: [['', 'deep-query', '']],
|
selectors: [['', 'deep-query', '']],
|
||||||
exportAs: ['deep-query'],
|
exportAs: ['deep-query'],
|
||||||
factory: () => new DeepQueryDirective(),
|
factory: () => new DeepQueryDirective(),
|
||||||
contentQueries: (dirIndex) => {
|
contentQueries: (dirIndex: number) => {
|
||||||
// @ContentChildren('foo', {descendants: false}) foos: QueryList<ElementRef>;
|
// @ContentChildren('foo', {descendants: false}) foos: QueryList<ElementRef>;
|
||||||
registerContentQuery(query(['foo'], true), dirIndex);
|
contentQuery(dirIndex, ['foo'], true);
|
||||||
},
|
},
|
||||||
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
|
contentQueriesRefresh: (dirIndex: number) => {
|
||||||
let tmp: any;
|
let tmp: any;
|
||||||
const instance = load<DeepQueryDirective>(dirIndex);
|
const instance = load<DeepQueryDirective>(dirIndex);
|
||||||
queryRefresh(tmp = loadQueryList<ElementRef>(queryStartIdx)) &&
|
queryRefresh(tmp = loadContentQuery<ElementRef>()) && (instance.foos = tmp);
|
||||||
(instance.foos = tmp);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue