diff --git a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts
index f7e3863652..8898992403 100644
--- a/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts
+++ b/packages/compiler-cli/test/compliance/r3_compiler_compliance_spec.ts
@@ -1150,11 +1150,12 @@ describe('compiler compliance', () => {
@Component({
selector: 'view-query-component',
template: \`
-
+
\`
})
export class ViewQueryComponent {
@ViewChild(SomeDirective) someDir: SomeDirective;
+ @ViewChildren(SomeDirective) someDirs: QueryList;
}
@NgModule({declarations: [SomeDirective, ViewQueryComponent]})
@@ -1205,8 +1206,8 @@ describe('compiler compliance', () => {
@Component({
selector: 'view-query-component',
template: \`
-
-
+
+
\`
})
export class ViewQueryComponent {
@@ -1221,15 +1222,15 @@ describe('compiler compliance', () => {
};
const ViewQueryComponentDefinition = `
- const $e0_attrs$ = ["myRef", ""];
- const $e1_attrs$ = ["myRef1", ""];
+ const $e0_attrs$ = ["myRef"];
+ const $e1_attrs$ = ["myRef1", "myRef2", "myRef3"];
…
ViewQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
…
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
if (rf & 1) {
- $r3$.ɵquery(0, ["myRef"], true);
- $r3$.ɵquery(1, ["myRef1", "myRef2", "myRef3"], true);
+ $r3$.ɵquery(0, $e0_attrs$, true);
+ $r3$.ɵquery(1, $e1_attrs$, true);
}
if (rf & 2) {
var $tmp$;
@@ -1249,19 +1250,24 @@ describe('compiler compliance', () => {
it('should support view queries with read tokens specified', () => {
const files = {
app: {
+ ...directive,
'view_query.component.ts': `
- import {Component, NgModule, ViewChild, ViewChildren, QueryList, ElementRef} from '@angular/core';
+ import {Component, NgModule, ViewChild, ViewChildren, QueryList, ElementRef, TemplateRef} from '@angular/core';
+ import {SomeDirective} from './some.directive';
@Component({
selector: 'view-query-component',
template: \`
-
-
+
+
+
\`
})
export class ViewQueryComponent {
- @ViewChild('myRef', {read: ElementRef}) myRef: any;
- @ViewChildren('myRef1, myRef2, myRef3', {read: ElementRef}) myRefs: QueryList;
+ @ViewChild('myRef', {read: TemplateRef}) myRef: TemplateRef;
+ @ViewChildren('myRef1, myRef2, myRef3', {read: ElementRef}) myRefs: QueryList;
+ @ViewChild(SomeDirective, {read: ElementRef}) someDir: ElementRef;
+ @ViewChildren(SomeDirective, {read: TemplateRef}) someDirs: QueryList;
}
@NgModule({declarations: [ViewQueryComponent]})
@@ -1271,20 +1277,24 @@ describe('compiler compliance', () => {
};
const ViewQueryComponentDefinition = `
- const $e0_attrs$ = ["myRef", ""];
- const $e1_attrs$ = ["myRef1", ""];
+ const $e0_attrs$ = ["myRef"];
+ const $e1_attrs$ = ["myRef1", "myRef2", "myRef3"];
…
ViewQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
…
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
if (rf & 1) {
- $r3$.ɵquery(0, ["myRef"], true, ElementRef);
- $r3$.ɵquery(1, ["myRef1", "myRef2", "myRef3"], true, ElementRef);
+ $r3$.ɵquery(0, $e0_attrs$, true, TemplateRef);
+ $r3$.ɵquery(1, SomeDirective, true, ElementRef);
+ $r3$.ɵquery(2, $e1_attrs$, true, ElementRef);
+ $r3$.ɵquery(3, SomeDirective, true, TemplateRef);
}
if (rf & 2) {
var $tmp$;
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(0))) && (ctx.myRef = $tmp$.first));
- ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(1))) && (ctx.myRefs = $tmp$));
+ ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(1))) && (ctx.someDir = $tmp$.first));
+ ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(2))) && (ctx.myRefs = $tmp$));
+ ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵload(3))) && (ctx.someDirs = $tmp$));
}
},
…
@@ -1366,104 +1376,112 @@ describe('compiler compliance', () => {
expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
});
- });
- it('should support content queries with local refs', () => {
- const files = {
- app: {
- 'content_query.component.ts': `
- import {Component, ContentChild, ContentChildren, NgModule, QueryList} from '@angular/core';
+ it('should support content queries with local refs', () => {
+ const files = {
+ app: {
+ 'content_query.component.ts': `
+ import {Component, ContentChild, ContentChildren, NgModule, QueryList} from '@angular/core';
- @Component({
- selector: 'content-query-component',
- template: \`
-
-
- \`
- })
- export class ContentQueryComponent {
- @ContentChild('myRef') myRef: any;
- @ContentChildren('myRef1, myRef2, myRef3') myRefs: QueryList;
+ @Component({
+ selector: 'content-query-component',
+ template: \`
+
+
+ \`
+ })
+ export class ContentQueryComponent {
+ @ContentChild('myRef') myRef: any;
+ @ContentChildren('myRef1, myRef2, myRef3') myRefs: QueryList;
+ }
+ @NgModule({declarations: [ContentQueryComponent]})
+ export class MyModule {}
+ `
}
+ };
- @NgModule({declarations: [ContentQueryComponent]})
- export class MyModule {}
- `
- }
- };
-
- const ContentQueryComponentDefinition = `
- const $e0_attrs$ = ["myRef", ""];
- const $e1_attrs$ = ["myRef1", ""];
- …
- ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
+ const ContentQueryComponentDefinition = `
+ const $e0_attrs$ = ["myRef"];
+ const $e1_attrs$ = ["myRef1", "myRef2", "myRef3"];
…
- contentQueries: function ContentQueryComponent_ContentQueries() {
- $r3$.ɵregisterContentQuery($r3$.ɵquery(null, ["myRef"], true));
- $r3$.ɵregisterContentQuery($r3$.ɵquery(null, ["myRef1", "myRef2", "myRef3"], false));
- },
- contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
- const instance = $r3$.ɵload(dirIndex);
- var $tmp$;
- ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
- ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.myRefs = $tmp$));
- },
- …
- });`;
+ ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
+ …
+ contentQueries: function ContentQueryComponent_ContentQueries() {
+ $r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$, true));
+ $r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false));
+ },
+ contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
+ const instance = $r3$.ɵload(dirIndex);
+ var $tmp$;
+ ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
+ ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.myRefs = $tmp$));
+ },
+ …
+ });`;
- const result = compile(files, angularFiles);
- const source = result.source;
+ const result = compile(files, angularFiles);
+ const source = result.source;
- expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
- });
+ expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
+ });
- it('should support content queries with read tokens specified', () => {
- const files = {
- app: {
- 'content_query.component.ts': `
- import {Component, ContentChild, ContentChildren, NgModule, QueryList, ElementRef} from '@angular/core';
+ it('should support content queries with read tokens specified', () => {
+ const files = {
+ app: {
+ ...directive,
+ 'content_query.component.ts': `
+ import {Component, ContentChild, ContentChildren, NgModule, QueryList, ElementRef, TemplateRef} from '@angular/core';
+ import {SomeDirective} from './some.directive';
- @Component({
- selector: 'content-query-component',
- template: \`
-
-
- \`
- })
- export class ContentQueryComponent {
- @ContentChild('myRef', {read: ElementRef}) myRef: any;
- @ContentChildren('myRef1, myRef2, myRef3', {read: ElementRef}) myRefs: QueryList;
+ @Component({
+ selector: 'content-query-component',
+ template: \`
+
+
+
+ \`
+ })
+ export class ContentQueryComponent {
+ @ContentChild('myRef', {read: TemplateRef}) myRef: TemplateRef;
+ @ContentChildren('myRef1, myRef2, myRef3', {read: ElementRef}) myRefs: QueryList;
+ @ContentChild(SomeDirective, {read: ElementRef}) someDir: ElementRef;
+ @ContentChildren(SomeDirective, {read: TemplateRef}) someDirs: QueryList;
+ }
+ @NgModule({declarations: [ContentQueryComponent]})
+ export class MyModule {}
+ `
}
+ };
- @NgModule({declarations: [ContentQueryComponent]})
- export class MyModule {}
- `
- }
- };
-
- const ContentQueryComponentDefinition = `
- const $e0_attrs$ = ["myRef", ""];
- const $e1_attrs$ = ["myRef1", ""];
- …
- ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
+ const ContentQueryComponentDefinition = `
+ const $e0_attrs$ = ["myRef"];
+ const $e1_attrs$ = ["myRef1", "myRef2", "myRef3"];
…
- contentQueries: function ContentQueryComponent_ContentQueries() {
- $r3$.ɵregisterContentQuery($r3$.ɵquery(null, ["myRef"], true, ElementRef));
- $r3$.ɵregisterContentQuery($r3$.ɵquery(null, ["myRef1", "myRef2", "myRef3"], false, ElementRef));
- },
- contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
- const instance = $r3$.ɵload(dirIndex);
- var $tmp$;
- ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
- ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.myRefs = $tmp$));
- },
- …
- });`;
+ ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
+ …
+ contentQueries: function ContentQueryComponent_ContentQueries() {
+ $r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e0_attrs$ , true, TemplateRef));
+ $r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, true, ElementRef));
+ $r3$.ɵregisterContentQuery($r3$.ɵquery(null, $e1_attrs$, false, ElementRef));
+ $r3$.ɵregisterContentQuery($r3$.ɵquery(null, SomeDirective, false, TemplateRef));
+ },
+ contentQueriesRefresh: function ContentQueryComponent_ContentQueriesRefresh(dirIndex, queryStartIndex) {
+ const instance = $r3$.ɵload(dirIndex);
+ var $tmp$;
+ ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList(queryStartIndex))) && (instance.myRef = $tmp$.first));
+ ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 1)))) && (instance.someDir = $tmp$.first));
+ ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 2)))) && (instance.myRefs = $tmp$));
+ ($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadQueryList((queryStartIndex + 3)))) && (instance.someDirs = $tmp$));
+ },
+ …
+ });`;
- const result = compile(files, angularFiles);
- const source = result.source;
+ const result = compile(files, angularFiles);
+ const source = result.source;
+
+ expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
+ });
- expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
});
describe('pipes', () => {
diff --git a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
index 140cb6d097..04b048b074 100644
--- a/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
+++ b/packages/compiler-cli/test/ngtsc/ngtsc_spec.ts
@@ -384,6 +384,14 @@ describe('ngtsc behavioral tests', () => {
});
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 = (id: number | null, descend: boolean, ref?: string): RegExp => {
+ const maybeRef = ref ? `, ${ref}` : ``;
+ return new RegExp(`i0\\.ɵquery\\(${id}, \\w+, ${descend}${maybeRef}\\)`);
+ };
+
env.tsconfig();
env.write(`test.ts`, `
import {Component, ContentChild, ContentChildren, TemplateRef, ViewChild} from '@angular/core';
@@ -406,11 +414,17 @@ describe('ngtsc behavioral tests', () => {
env.driveMain();
const jsContents = env.getContents('test.js');
- expect(jsContents).toContain(`i0.ɵquery(null, ["bar"], true, TemplateRef)`);
+ expect(jsContents).toMatch(varRegExp('bar'));
+ expect(jsContents).toMatch(varRegExp('test1'));
+ expect(jsContents).toMatch(varRegExp('test2'));
+ expect(jsContents).toMatch(varRegExp('accessor'));
expect(jsContents).toContain(`i0.ɵquery(null, TemplateRef, false)`);
- expect(jsContents).toContain(`i0.ɵquery(null, ["test2"], true)`);
- expect(jsContents).toContain(`i0.ɵquery(0, ["accessor"], true)`);
- expect(jsContents).toContain(`i0.ɵquery(1, ["test1"], true)`);
+ expect(jsContents)
+ .toMatch(queryRegExp(
+ null, true, 'TemplateRef')); // match `i0.ɵquery(null, _c0, true, TemplateRef)`
+ expect(jsContents).toMatch(queryRegExp(null, true)); // match `i0.ɵquery(null, _c0, true)`
+ expect(jsContents).toMatch(queryRegExp(0, true)); // match `i0.ɵquery(0, _c0, true)`
+ expect(jsContents).toMatch(queryRegExp(1, true)); // match `i0.ɵquery(1, _c0, true)`
});
it('should handle queries that use forwardRef', () => {
diff --git a/packages/compiler/src/render3/view/util.ts b/packages/compiler/src/render3/view/util.ts
index 07db9e71da..55c6174840 100644
--- a/packages/compiler/src/render3/view/util.ts
+++ b/packages/compiler/src/render3/view/util.ts
@@ -112,7 +112,7 @@ export function getQueryPredicate(
const selectors = selector.split(',').map(token => o.literal(token.trim()));
predicate.push(...selectors);
});
- return constantPool.getConstLiteral(o.literalArr(predicate));
+ return constantPool.getConstLiteral(o.literalArr(predicate), true);
} else {
return query.predicate;
}