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

This commit adds support for the `static: true` flag in `ContentChild`
queries. Prior to this commit, all `ContentChild` 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
@ContentChild(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 18:18:56 -08:00
committed by Igor Minar
parent a4638d5a81
commit 3c1a1620e3
10 changed files with 261 additions and 50 deletions

View File

@ -1694,6 +1694,79 @@ describe('compiler compliance', () => {
expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
});
it('should support static content queries', () => {
const files = {
app: {
...directive,
'content_query.ts': `
import {Component, ContentChild, NgModule} from '@angular/core';
import {SomeDirective} from './some.directive';
@Component({
selector: 'content-query-component',
template: \`
<div><ng-content></ng-content></div>
\`
})
export class ContentQueryComponent {
@ContentChild(SomeDirective, {static: true}) someDir !: SomeDirective;
@ContentChild('foo', {static: false}) foo !: ElementRef;
}
@Component({
selector: 'my-app',
template: \`
<content-query-component>
<div someDir></div>
</content-query-component>
\`
})
export class MyApp { }
@NgModule({declarations: [SomeDirective, ContentQueryComponent, MyApp]})
export class MyModule { }
`
}
};
const ContentQueryComponentDefinition = `
ContentQueryComponent.ngComponentDef = $r3$.ɵdefineComponent({
type: ContentQueryComponent,
selectors: [["content-query-component"]],
factory: function ContentQueryComponent_Factory(t) {
return new (t || ContentQueryComponent)();
},
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
if (rf & 1) {
$r3$.ɵstaticContentQuery(dirIndex, SomeDirective, true, null);
$r3$.ɵcontentQuery(dirIndex, $ref0$, true, null);
}
if (rf & 2) {
var $tmp$;
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (ctx.someDir = $tmp$.first));
($r3$.ɵqueryRefresh(($tmp$ = $r3$.ɵloadContentQuery())) && (ctx.foo = $tmp$.first));
}
},
ngContentSelectors: $_c1$,
consts: 2,
vars: 0,
template: function ContentQueryComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵprojectionDef();
$r3$.ɵelementStart(0, "div");
$r3$.ɵprojection(1);
$r3$.ɵelementEnd();
}
},
encapsulation: 2
});`;
const result = compile(files, angularFiles);
const source = result.source;
expectEmit(source, ContentQueryComponentDefinition, 'Invalid ContentQuery declaration');
});
it('should support content queries with read tokens specified', () => {
const files = {
app: {