fix(ivy): support static ViewChild queries (#28811)

This commit adds support for the `static: true` flag in
`ViewChild` queries. Prior to this commit, all `ViewChild`
queries were resolved after change detection ran. This is
a problem for backwards compatibility because View Engine
also supported "static" queries which would resolve before
change detection.

Now if users add a `static: true` option, the query will be
resolved in creation mode (before change detection runs).
For example:

```ts
@ViewChild(TemplateRef, {static: true}) template !: TemplateRef;
```

This feature will come in handy for components that need
to create components dynamically.

PR Close #28811
This commit is contained in:
Kara Erickson
2019-02-18 17:33:59 -08:00
committed by Igor Minar
parent ae16378ee7
commit a4638d5a81
26 changed files with 340 additions and 163 deletions

View File

@ -1376,8 +1376,8 @@ describe('compiler compliance', () => {
factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); },
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
if (rf & 1) {
$r3$.ɵviewQuery(SomeDirective, true);
$r3$.ɵviewQuery(SomeDirective, true);
$r3$.ɵviewQuery(SomeDirective, true, null);
$r3$.ɵviewQuery(SomeDirective, true, null);
}
if (rf & 2) {
var $tmp$;
@ -1434,8 +1434,8 @@ describe('compiler compliance', () => {
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
if (rf & 1) {
$r3$.ɵviewQuery($e0_attrs$, true);
$r3$.ɵviewQuery($e1_attrs$, true);
$r3$.ɵviewQuery($e0_attrs$, true, null);
$r3$.ɵviewQuery($e1_attrs$, true, null);
}
if (rf & 2) {
var $tmp$;
@ -1452,6 +1452,67 @@ describe('compiler compliance', () => {
expectEmit(source, ViewQueryComponentDefinition, 'Invalid ViewQuery declaration');
});
it('should support static view queries', () => {
const files = {
app: {
...directive,
'view_query.component.ts': `
import {Component, NgModule, ViewChild} from '@angular/core';
import {SomeDirective} from './some.directive';
@Component({
selector: 'view-query-component',
template: \`
<div someDir></div>
\`
})
export class ViewQueryComponent {
@ViewChild(SomeDirective, {static: true}) someDir !: SomeDirective;
@ViewChild('foo', {static: false}) foo !: ElementRef;
}
@NgModule({declarations: [SomeDirective, ViewQueryComponent]})
export class MyModule {}
`
}
};
const ViewQueryComponentDefinition = `
const $refs$ = ["foo"];
const $e0_attrs$ = ["someDir",""];
ViewQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
type: ViewQueryComponent,
selectors: [["view-query-component"]],
factory: function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); },
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
if (rf & 1) {
$r3$.ɵstaticViewQuery(SomeDirective, true, null);
$r3$.ɵviewQuery($refs$, true, null);
}
if (rf & 2) {
var $tmp$;
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.someDir = $tmp$.first));
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadViewQuery())) && (ctx.foo = $tmp$.first));
}
},
consts: 1,
vars: 0,
template: function ViewQueryComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵelement(0, "div", $e0_attrs$);
}
},
directives: function () { return [SomeDirective]; },
encapsulation: 2
});`;
const result = compile(files, angularFiles);
const source = result.source;
expectEmit(source, ViewQueryComponentDefinition, 'Invalid ViewQuery declaration');
});
it('should support view queries with read tokens specified', () => {
const files = {
app: {
@ -1555,8 +1616,8 @@ describe('compiler compliance', () => {
},
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
if (rf & 1) {
$r3$.ɵcontentQuery(dirIndex, SomeDirective, true);
$r3$.ɵcontentQuery(dirIndex, SomeDirective, false);
$r3$.ɵcontentQuery(dirIndex, SomeDirective, true, null);
$r3$.ɵcontentQuery(dirIndex, SomeDirective, false, null);
}
if (rf & 2) {
var $tmp$;
@ -1615,8 +1676,8 @@ describe('compiler compliance', () => {
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
if (rf & 1) {
$r3$.ɵcontentQuery(dirIndex, $e0_attrs$, true);
$r3$.ɵcontentQuery(dirIndex, $e1_attrs$, false);
$r3$.ɵcontentQuery(dirIndex, $e0_attrs$, true, null);
$r3$.ɵcontentQuery(dirIndex, $e1_attrs$, false, null);
}
if (rf & 2) {
var $tmp$;