2019-02-08 17:11:33 -05:00
|
|
|
/**
|
|
|
|
* @license
|
|
|
|
* Copyright Google Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
|
|
* found in the LICENSE file at https://angular.io/license
|
|
|
|
*/
|
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
import {Component, ContentChild, ContentChildren, Directive, ElementRef, Input, QueryList, TemplateRef, Type, ViewChild, ViewChildren} from '@angular/core';
|
2019-02-08 17:11:33 -05:00
|
|
|
import {TestBed} from '@angular/core/testing';
|
|
|
|
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
2019-02-18 21:18:56 -05:00
|
|
|
import {onlyInIvy} from '@angular/private/testing';
|
2019-02-08 17:11:33 -05:00
|
|
|
|
|
|
|
describe('query logic', () => {
|
|
|
|
beforeEach(() => {
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
TestBed.configureTestingModule({
|
|
|
|
declarations: [
|
|
|
|
AppComp, QueryComp, SimpleCompA, SimpleCompB, StaticViewQueryComp, TextDirective,
|
2019-02-18 20:33:59 -05:00
|
|
|
SubclassStaticViewQueryComp, StaticContentQueryComp, SubclassStaticContentQueryComp,
|
2019-03-13 14:30:38 -04:00
|
|
|
QueryCompWithChanges, StaticContentQueryDir, SuperDirectiveQueryTarget, SuperDirective,
|
|
|
|
SubComponent
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
]
|
|
|
|
});
|
2019-02-08 17:11:33 -05:00
|
|
|
});
|
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
describe('view queries', () => {
|
|
|
|
it('should return Component instances when Components are labeled and retrieved', () => {
|
|
|
|
const template = `
|
|
|
|
<div><simple-comp-a #viewQuery></simple-comp-a></div>
|
|
|
|
<div><simple-comp-b #viewQuery></simple-comp-b></div>
|
|
|
|
`;
|
|
|
|
const fixture = initWithTemplate(QueryComp, template);
|
|
|
|
const comp = fixture.componentInstance;
|
|
|
|
expect(comp.viewChild).toBeAnInstanceOf(SimpleCompA);
|
|
|
|
expect(comp.viewChildren.first).toBeAnInstanceOf(SimpleCompA);
|
|
|
|
expect(comp.viewChildren.last).toBeAnInstanceOf(SimpleCompB);
|
|
|
|
});
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
it('should return ElementRef when HTML element is labeled and retrieved', () => {
|
|
|
|
const template = `
|
2019-02-08 17:11:33 -05:00
|
|
|
<div #viewQuery></div>
|
|
|
|
`;
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
const fixture = initWithTemplate(QueryComp, template);
|
|
|
|
const comp = fixture.componentInstance;
|
|
|
|
expect(comp.viewChild).toBeAnInstanceOf(ElementRef);
|
|
|
|
expect(comp.viewChildren.first).toBeAnInstanceOf(ElementRef);
|
|
|
|
});
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
onlyInIvy('multiple local refs are supported in Ivy')
|
|
|
|
.it('should return ElementRefs when HTML elements are labeled and retrieved', () => {
|
|
|
|
const template = `
|
2019-02-08 17:11:33 -05:00
|
|
|
<div #viewQuery #first>A</div>
|
|
|
|
<div #viewQuery #second>B</div>
|
|
|
|
`;
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
const fixture = initWithTemplate(QueryComp, template);
|
|
|
|
const comp = fixture.componentInstance;
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
expect(comp.viewChild).toBeAnInstanceOf(ElementRef);
|
|
|
|
expect(comp.viewChild.nativeElement).toBe(fixture.debugElement.children[0].nativeElement);
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
expect(comp.viewChildren.first).toBeAnInstanceOf(ElementRef);
|
|
|
|
expect(comp.viewChildren.last).toBeAnInstanceOf(ElementRef);
|
|
|
|
expect(comp.viewChildren.length).toBe(2);
|
|
|
|
});
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
it('should return TemplateRef when template is labeled and retrieved', () => {
|
|
|
|
const template = `
|
2019-02-08 17:11:33 -05:00
|
|
|
<ng-template #viewQuery></ng-template>
|
|
|
|
`;
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
const fixture = initWithTemplate(QueryComp, template);
|
|
|
|
const comp = fixture.componentInstance;
|
|
|
|
expect(comp.viewChildren.first).toBeAnInstanceOf(TemplateRef);
|
|
|
|
});
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
onlyInIvy('multiple local refs are supported in Ivy')
|
|
|
|
.it('should return TemplateRefs when templates are labeled and retrieved', () => {
|
|
|
|
const template = `
|
2019-02-08 17:11:33 -05:00
|
|
|
<ng-template #viewQuery></ng-template>
|
|
|
|
<ng-template #viewQuery></ng-template>
|
|
|
|
`;
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
const fixture = initWithTemplate(QueryComp, template);
|
|
|
|
const comp = fixture.componentInstance;
|
|
|
|
expect(comp.viewChild).toBeAnInstanceOf(TemplateRef);
|
|
|
|
expect(comp.viewChild.elementRef.nativeElement)
|
|
|
|
.toBe(fixture.debugElement.childNodes[0].nativeNode);
|
|
|
|
|
|
|
|
expect(comp.viewChildren.first).toBeAnInstanceOf(TemplateRef);
|
|
|
|
expect(comp.viewChildren.last).toBeAnInstanceOf(TemplateRef);
|
|
|
|
expect(comp.viewChildren.length).toBe(2);
|
|
|
|
});
|
2019-02-08 17:11:33 -05:00
|
|
|
|
2019-02-18 20:33:59 -05:00
|
|
|
it('should set static view child queries in creation mode (and just in creation mode)', () => {
|
|
|
|
const fixture = TestBed.createComponent(StaticViewQueryComp);
|
|
|
|
const component = fixture.componentInstance;
|
|
|
|
|
|
|
|
// static ViewChild query should be set in creation mode, before CD runs
|
|
|
|
expect(component.textDir).toBeAnInstanceOf(TextDirective);
|
|
|
|
expect(component.textDir.text).toEqual('');
|
|
|
|
expect(component.setEvents).toEqual(['textDir set']);
|
|
|
|
|
|
|
|
// dynamic ViewChild query should not have been resolved yet
|
|
|
|
expect(component.foo).not.toBeDefined();
|
|
|
|
|
|
|
|
const span = fixture.nativeElement.querySelector('span');
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(component.textDir.text).toEqual('some text');
|
|
|
|
expect(component.foo.nativeElement).toBe(span);
|
|
|
|
expect(component.setEvents).toEqual(['textDir set', 'foo set']);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support static view child queries inherited from superclasses', () => {
|
|
|
|
const fixture = TestBed.createComponent(SubclassStaticViewQueryComp);
|
|
|
|
const component = fixture.componentInstance;
|
|
|
|
const divs = fixture.nativeElement.querySelectorAll('div');
|
|
|
|
const spans = fixture.nativeElement.querySelectorAll('span');
|
|
|
|
|
|
|
|
// static ViewChild queries should be set in creation mode, before CD runs
|
|
|
|
expect(component.textDir).toBeAnInstanceOf(TextDirective);
|
|
|
|
expect(component.textDir.text).toEqual('');
|
|
|
|
expect(component.bar.nativeElement).toEqual(divs[1]);
|
|
|
|
|
|
|
|
// dynamic ViewChild queries should not have been resolved yet
|
|
|
|
expect(component.foo).not.toBeDefined();
|
|
|
|
expect(component.baz).not.toBeDefined();
|
|
|
|
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(component.textDir.text).toEqual('some text');
|
|
|
|
expect(component.foo.nativeElement).toBe(spans[0]);
|
|
|
|
expect(component.baz.nativeElement).toBe(spans[1]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support multiple static view queries (multiple template passes)', () => {
|
|
|
|
const template = `
|
|
|
|
<static-view-query-comp></static-view-query-comp>
|
|
|
|
<static-view-query-comp></static-view-query-comp>
|
|
|
|
`;
|
|
|
|
TestBed.overrideComponent(AppComp, {set: new Component({template})});
|
|
|
|
const fixture = TestBed.createComponent(AppComp);
|
|
|
|
|
|
|
|
const firstComponent = fixture.debugElement.children[0].injector.get(StaticViewQueryComp);
|
|
|
|
const secondComponent = fixture.debugElement.children[1].injector.get(StaticViewQueryComp);
|
|
|
|
|
|
|
|
// static ViewChild query should be set in creation mode, before CD runs
|
|
|
|
expect(firstComponent.textDir).toBeAnInstanceOf(TextDirective);
|
|
|
|
expect(secondComponent.textDir).toBeAnInstanceOf(TextDirective);
|
|
|
|
expect(firstComponent.textDir.text).toEqual('');
|
|
|
|
expect(secondComponent.textDir.text).toEqual('');
|
|
|
|
expect(firstComponent.setEvents).toEqual(['textDir set']);
|
|
|
|
expect(secondComponent.setEvents).toEqual(['textDir set']);
|
|
|
|
|
|
|
|
// dynamic ViewChild query should not have been resolved yet
|
|
|
|
expect(firstComponent.foo).not.toBeDefined();
|
|
|
|
expect(secondComponent.foo).not.toBeDefined();
|
|
|
|
|
|
|
|
const spans = fixture.nativeElement.querySelectorAll('span');
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(firstComponent.textDir.text).toEqual('some text');
|
|
|
|
expect(secondComponent.textDir.text).toEqual('some text');
|
|
|
|
expect(firstComponent.foo.nativeElement).toBe(spans[0]);
|
|
|
|
expect(secondComponent.foo.nativeElement).toBe(spans[1]);
|
|
|
|
expect(firstComponent.setEvents).toEqual(['textDir set', 'foo set']);
|
|
|
|
expect(secondComponent.setEvents).toEqual(['textDir set', 'foo set']);
|
|
|
|
});
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
|
2019-03-13 14:30:38 -04:00
|
|
|
it('should allow for view queries to be inherited from a directive', () => {
|
|
|
|
const fixture = TestBed.createComponent(SubComponent);
|
|
|
|
const comp = fixture.componentInstance;
|
|
|
|
fixture.detectChanges();
|
|
|
|
|
|
|
|
expect(comp.headers).toBeTruthy();
|
|
|
|
expect(comp.headers.length).toBe(2);
|
|
|
|
expect(comp.headers.toArray().every(result => result instanceof SuperDirectiveQueryTarget))
|
|
|
|
.toBe(true);
|
|
|
|
});
|
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
describe('content queries', () => {
|
|
|
|
it('should return Component instance when Component is labeled and retrieved', () => {
|
|
|
|
const template = `
|
|
|
|
<local-ref-query-component #q>
|
|
|
|
<simple-comp-a #contentQuery></simple-comp-a>
|
|
|
|
</local-ref-query-component>
|
|
|
|
`;
|
|
|
|
const fixture = initWithTemplate(AppComp, template);
|
|
|
|
const comp = fixture.debugElement.children[0].references['q'];
|
|
|
|
expect(comp.contentChild).toBeAnInstanceOf(SimpleCompA);
|
|
|
|
expect(comp.contentChildren.first).toBeAnInstanceOf(SimpleCompA);
|
|
|
|
});
|
|
|
|
|
|
|
|
onlyInIvy('multiple local refs are supported in Ivy')
|
|
|
|
.it('should return Component instances when Components are labeled and retrieved', () => {
|
|
|
|
const template = `
|
|
|
|
<local-ref-query-component #q>
|
|
|
|
<simple-comp-a #contentQuery></simple-comp-a>
|
|
|
|
<simple-comp-b #contentQuery></simple-comp-b>
|
|
|
|
</local-ref-query-component>
|
|
|
|
`;
|
|
|
|
const fixture = initWithTemplate(AppComp, template);
|
|
|
|
const comp = fixture.debugElement.children[0].references['q'];
|
|
|
|
expect(comp.contentChild).toBeAnInstanceOf(SimpleCompA);
|
|
|
|
expect(comp.contentChildren.first).toBeAnInstanceOf(SimpleCompA);
|
|
|
|
expect(comp.contentChildren.last).toBeAnInstanceOf(SimpleCompB);
|
|
|
|
expect(comp.contentChildren.length).toBe(2);
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
it('should return ElementRef when HTML element is labeled and retrieved', () => {
|
|
|
|
const template = `
|
2019-02-08 17:11:33 -05:00
|
|
|
<local-ref-query-component #q>
|
|
|
|
<div #contentQuery></div>
|
|
|
|
</local-ref-query-component>
|
|
|
|
`;
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
const fixture = initWithTemplate(AppComp, template);
|
|
|
|
const comp = fixture.debugElement.children[0].references['q'];
|
|
|
|
expect(comp.contentChildren.first).toBeAnInstanceOf(ElementRef);
|
|
|
|
});
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
onlyInIvy('multiple local refs are supported in Ivy')
|
|
|
|
.it('should return ElementRefs when HTML elements are labeled and retrieved', () => {
|
|
|
|
const template = `
|
2019-02-08 17:11:33 -05:00
|
|
|
<local-ref-query-component #q>
|
|
|
|
<div #contentQuery></div>
|
|
|
|
<div #contentQuery></div>
|
|
|
|
</local-ref-query-component>
|
|
|
|
`;
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
const fixture = initWithTemplate(AppComp, template);
|
|
|
|
const firstChild = fixture.debugElement.children[0];
|
|
|
|
const comp = firstChild.references['q'];
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
expect(comp.contentChild).toBeAnInstanceOf(ElementRef);
|
|
|
|
expect(comp.contentChild.nativeElement).toBe(firstChild.children[0].nativeElement);
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
expect(comp.contentChildren.first).toBeAnInstanceOf(ElementRef);
|
|
|
|
expect(comp.contentChildren.last).toBeAnInstanceOf(ElementRef);
|
|
|
|
expect(comp.contentChildren.length).toBe(2);
|
|
|
|
});
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
it('should return TemplateRef when template is labeled and retrieved', () => {
|
|
|
|
const template = `
|
2019-02-08 17:11:33 -05:00
|
|
|
<local-ref-query-component #q>
|
|
|
|
<ng-template #contentQuery></ng-template>
|
|
|
|
</local-ref-query-component>
|
|
|
|
`;
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
const fixture = initWithTemplate(AppComp, template);
|
|
|
|
const comp = fixture.debugElement.children[0].references['q'];
|
|
|
|
expect(comp.contentChildren.first).toBeAnInstanceOf(TemplateRef);
|
|
|
|
});
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
onlyInIvy('multiple local refs are supported in Ivy')
|
|
|
|
.it('should return TemplateRefs when templates are labeled and retrieved', () => {
|
|
|
|
const template = `
|
2019-02-08 17:11:33 -05:00
|
|
|
<local-ref-query-component #q>
|
|
|
|
<ng-template #contentQuery></ng-template>
|
|
|
|
<ng-template #contentQuery></ng-template>
|
|
|
|
</local-ref-query-component>
|
|
|
|
`;
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
const fixture = initWithTemplate(AppComp, template);
|
|
|
|
const firstChild = fixture.debugElement.children[0];
|
|
|
|
const comp = firstChild.references['q'];
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
expect(comp.contentChild).toBeAnInstanceOf(TemplateRef);
|
|
|
|
expect(comp.contentChild.elementRef.nativeElement)
|
|
|
|
.toBe(firstChild.childNodes[0].nativeNode);
|
2019-02-08 17:11:33 -05:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
expect(comp.contentChildren.first).toBeAnInstanceOf(TemplateRef);
|
|
|
|
expect(comp.contentChildren.last).toBeAnInstanceOf(TemplateRef);
|
|
|
|
expect(comp.contentChildren.length).toBe(2);
|
|
|
|
});
|
|
|
|
|
2019-02-18 21:18:56 -05:00
|
|
|
it('should set static content child queries in creation mode (and just in creation mode)',
|
|
|
|
() => {
|
|
|
|
const template = `
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
<static-content-query-comp>
|
|
|
|
<div [text]="text"></div>
|
|
|
|
<span #foo></span>
|
|
|
|
</static-content-query-comp>
|
|
|
|
`;
|
2019-02-18 21:18:56 -05:00
|
|
|
TestBed.overrideComponent(AppComp, {set: new Component({template})});
|
|
|
|
const fixture = TestBed.createComponent(AppComp);
|
|
|
|
const component = fixture.debugElement.children[0].injector.get(StaticContentQueryComp);
|
|
|
|
|
|
|
|
// static ContentChild query should be set in creation mode, before CD runs
|
|
|
|
expect(component.textDir).toBeAnInstanceOf(TextDirective);
|
|
|
|
expect(component.textDir.text).toEqual('');
|
|
|
|
expect(component.setEvents).toEqual(['textDir set']);
|
|
|
|
|
|
|
|
// dynamic ContentChild query should not have been resolved yet
|
|
|
|
expect(component.foo).not.toBeDefined();
|
|
|
|
|
|
|
|
const span = fixture.nativeElement.querySelector('span');
|
|
|
|
(fixture.componentInstance as any).text = 'some text';
|
|
|
|
fixture.detectChanges();
|
|
|
|
|
|
|
|
expect(component.textDir.text).toEqual('some text');
|
|
|
|
expect(component.foo.nativeElement).toBe(span);
|
|
|
|
expect(component.setEvents).toEqual(['textDir set', 'foo set']);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support static content child queries inherited from superclasses', () => {
|
|
|
|
const template = `
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
<subclass-static-content-query-comp>
|
|
|
|
<div [text]="text"></div>
|
|
|
|
<span #foo></span>
|
|
|
|
<div #bar></div>
|
|
|
|
<span #baz></span>
|
|
|
|
</subclass-static-content-query-comp>
|
|
|
|
`;
|
2019-02-18 21:18:56 -05:00
|
|
|
TestBed.overrideComponent(AppComp, {set: new Component({template})});
|
|
|
|
const fixture = TestBed.createComponent(AppComp);
|
|
|
|
const component =
|
|
|
|
fixture.debugElement.children[0].injector.get(SubclassStaticContentQueryComp);
|
|
|
|
const divs = fixture.nativeElement.querySelectorAll('div');
|
|
|
|
const spans = fixture.nativeElement.querySelectorAll('span');
|
|
|
|
|
|
|
|
// static ContentChild queries should be set in creation mode, before CD runs
|
|
|
|
expect(component.textDir).toBeAnInstanceOf(TextDirective);
|
|
|
|
expect(component.textDir.text).toEqual('');
|
|
|
|
expect(component.bar.nativeElement).toEqual(divs[1]);
|
|
|
|
|
|
|
|
// dynamic ContentChild queries should not have been resolved yet
|
|
|
|
expect(component.foo).not.toBeDefined();
|
|
|
|
expect(component.baz).not.toBeDefined();
|
|
|
|
|
|
|
|
(fixture.componentInstance as any).text = 'some text';
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(component.textDir.text).toEqual('some text');
|
|
|
|
expect(component.foo.nativeElement).toBe(spans[0]);
|
|
|
|
expect(component.baz.nativeElement).toBe(spans[1]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set static content child queries on directives', () => {
|
|
|
|
const template = `
|
|
|
|
<div staticContentQueryDir>
|
|
|
|
<div [text]="text"></div>
|
|
|
|
<span #foo></span>
|
|
|
|
</div>
|
|
|
|
`;
|
|
|
|
TestBed.overrideComponent(AppComp, {set: new Component({template})});
|
|
|
|
const fixture = TestBed.createComponent(AppComp);
|
|
|
|
const component = fixture.debugElement.children[0].injector.get(StaticContentQueryDir);
|
|
|
|
|
|
|
|
// static ContentChild query should be set in creation mode, before CD runs
|
|
|
|
expect(component.textDir).toBeAnInstanceOf(TextDirective);
|
|
|
|
expect(component.textDir.text).toEqual('');
|
|
|
|
expect(component.setEvents).toEqual(['textDir set']);
|
|
|
|
|
|
|
|
// dynamic ContentChild query should not have been resolved yet
|
|
|
|
expect(component.foo).not.toBeDefined();
|
|
|
|
|
|
|
|
const span = fixture.nativeElement.querySelector('span');
|
|
|
|
(fixture.componentInstance as any).text = 'some text';
|
|
|
|
fixture.detectChanges();
|
|
|
|
|
|
|
|
expect(component.textDir.text).toEqual('some text');
|
|
|
|
expect(component.foo.nativeElement).toBe(span);
|
|
|
|
expect(component.setEvents).toEqual(['textDir set', 'foo set']);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should support multiple content query components (multiple template passes)', () => {
|
|
|
|
const template = `
|
|
|
|
<static-content-query-comp>
|
|
|
|
<div [text]="text"></div>
|
|
|
|
<span #foo></span>
|
|
|
|
</static-content-query-comp>
|
|
|
|
<static-content-query-comp>
|
|
|
|
<div [text]="text"></div>
|
|
|
|
<span #foo></span>
|
|
|
|
</static-content-query-comp>
|
|
|
|
`;
|
|
|
|
TestBed.overrideComponent(AppComp, {set: new Component({template})});
|
|
|
|
const fixture = TestBed.createComponent(AppComp);
|
|
|
|
const firstComponent = fixture.debugElement.children[0].injector.get(StaticContentQueryComp);
|
|
|
|
const secondComponent = fixture.debugElement.children[1].injector.get(StaticContentQueryComp);
|
|
|
|
|
|
|
|
// static ContentChild query should be set in creation mode, before CD runs
|
|
|
|
expect(firstComponent.textDir).toBeAnInstanceOf(TextDirective);
|
|
|
|
expect(secondComponent.textDir).toBeAnInstanceOf(TextDirective);
|
|
|
|
expect(firstComponent.textDir.text).toEqual('');
|
|
|
|
expect(secondComponent.textDir.text).toEqual('');
|
|
|
|
expect(firstComponent.setEvents).toEqual(['textDir set']);
|
|
|
|
expect(secondComponent.setEvents).toEqual(['textDir set']);
|
|
|
|
|
|
|
|
// dynamic ContentChild query should not have been resolved yet
|
|
|
|
expect(firstComponent.foo).not.toBeDefined();
|
|
|
|
expect(secondComponent.foo).not.toBeDefined();
|
|
|
|
|
|
|
|
const spans = fixture.nativeElement.querySelectorAll('span');
|
|
|
|
(fixture.componentInstance as any).text = 'some text';
|
|
|
|
fixture.detectChanges();
|
|
|
|
|
|
|
|
expect(firstComponent.textDir.text).toEqual('some text');
|
|
|
|
expect(secondComponent.textDir.text).toEqual('some text');
|
|
|
|
|
|
|
|
expect(firstComponent.foo.nativeElement).toBe(spans[0]);
|
|
|
|
expect(secondComponent.foo.nativeElement).toBe(spans[1]);
|
|
|
|
|
|
|
|
expect(firstComponent.setEvents).toEqual(['textDir set', 'foo set']);
|
|
|
|
expect(secondComponent.setEvents).toEqual(['textDir set', 'foo set']);
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
|
2019-03-11 09:26:20 -04:00
|
|
|
describe('descendants', () => {
|
|
|
|
|
|
|
|
it('should match directives on elements that used to be wrapped by a required parent in HTML parser',
|
|
|
|
() => {
|
|
|
|
|
|
|
|
@Directive({selector: '[myDef]'})
|
|
|
|
class MyDef {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({selector: 'my-container', template: ``})
|
|
|
|
class MyContainer {
|
|
|
|
@ContentChildren(MyDef) myDefs !: QueryList<MyDef>;
|
|
|
|
}
|
|
|
|
@Component(
|
|
|
|
{selector: 'test-cmpt', template: `<my-container><tr myDef></tr></my-container>`})
|
|
|
|
class TestCmpt {
|
|
|
|
}
|
|
|
|
|
|
|
|
TestBed.configureTestingModule({declarations: [TestCmpt, MyContainer, MyDef]});
|
|
|
|
const fixture = TestBed.createComponent(TestCmpt);
|
|
|
|
const cmptWithQuery = fixture.debugElement.children[0].injector.get(MyContainer);
|
|
|
|
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(cmptWithQuery.myDefs.length).toBe(1);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2019-02-18 20:33:59 -05:00
|
|
|
describe('observable interface', () => {
|
|
|
|
|
|
|
|
it('should allow observing changes to query list', () => {
|
|
|
|
const fixture = TestBed.createComponent(QueryCompWithChanges);
|
|
|
|
let changes = 0;
|
|
|
|
fixture.detectChanges();
|
|
|
|
|
|
|
|
fixture.componentInstance.foos.changes.subscribe((value: any) => {
|
|
|
|
changes += 1;
|
|
|
|
expect(value).toBe(fixture.componentInstance.foos);
|
|
|
|
});
|
|
|
|
|
|
|
|
// refresh without setting dirty - no emit
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(changes).toBe(0);
|
|
|
|
|
|
|
|
// refresh with setting dirty - emit
|
|
|
|
fixture.componentInstance.showing = true;
|
|
|
|
fixture.detectChanges();
|
|
|
|
expect(changes).toBe(1);
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
|
2019-02-08 17:11:33 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
function initWithTemplate(compType: Type<any>, template: string) {
|
|
|
|
TestBed.overrideComponent(compType, {set: new Component({template})});
|
|
|
|
const fixture = TestBed.createComponent(compType);
|
|
|
|
fixture.detectChanges();
|
|
|
|
return fixture;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({selector: 'local-ref-query-component', template: '<ng-content></ng-content>'})
|
|
|
|
class QueryComp {
|
|
|
|
@ViewChild('viewQuery') viewChild !: any;
|
|
|
|
@ContentChild('contentQuery') contentChild !: any;
|
|
|
|
|
|
|
|
@ViewChildren('viewQuery') viewChildren !: QueryList<any>;
|
|
|
|
@ContentChildren('contentQuery') contentChildren !: QueryList<any>;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({selector: 'app-comp', template: ``})
|
|
|
|
class AppComp {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({selector: 'simple-comp-a', template: ''})
|
|
|
|
class SimpleCompA {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({selector: 'simple-comp-b', template: ''})
|
|
|
|
class SimpleCompB {
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
@Directive({selector: '[text]'})
|
|
|
|
class TextDirective {
|
|
|
|
@Input() text = '';
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'static-view-query-comp',
|
|
|
|
template: `
|
|
|
|
<div [text]="text"></div>
|
|
|
|
<span #foo></span>
|
|
|
|
`
|
|
|
|
})
|
|
|
|
class StaticViewQueryComp {
|
|
|
|
private _textDir !: TextDirective;
|
|
|
|
private _foo !: ElementRef;
|
|
|
|
setEvents: string[] = [];
|
|
|
|
|
|
|
|
@ViewChild(TextDirective, {static: true})
|
|
|
|
get textDir(): TextDirective { return this._textDir; }
|
|
|
|
|
|
|
|
set textDir(value: TextDirective) {
|
|
|
|
this.setEvents.push('textDir set');
|
|
|
|
this._textDir = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@ViewChild('foo', {static: false})
|
|
|
|
get foo(): ElementRef { return this._foo; }
|
|
|
|
|
|
|
|
set foo(value: ElementRef) {
|
|
|
|
this.setEvents.push('foo set');
|
|
|
|
this._foo = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
text = 'some text';
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'subclass-static-view-query-comp',
|
|
|
|
template: `
|
|
|
|
<div [text]="text"></div>
|
|
|
|
<span #foo></span>
|
2019-03-13 14:30:38 -04:00
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
<div #bar></div>
|
|
|
|
<span #baz></span>
|
|
|
|
`
|
|
|
|
})
|
|
|
|
class SubclassStaticViewQueryComp extends StaticViewQueryComp {
|
|
|
|
@ViewChild('bar', {static: true})
|
|
|
|
bar !: ElementRef;
|
|
|
|
|
|
|
|
@ViewChild('baz', {static: false})
|
|
|
|
baz !: ElementRef;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Component({selector: 'static-content-query-comp', template: `<ng-content></ng-content>`})
|
|
|
|
class StaticContentQueryComp {
|
|
|
|
private _textDir !: TextDirective;
|
|
|
|
private _foo !: ElementRef;
|
|
|
|
setEvents: string[] = [];
|
|
|
|
|
|
|
|
@ContentChild(TextDirective, {static: true})
|
|
|
|
get textDir(): TextDirective { return this._textDir; }
|
|
|
|
|
|
|
|
set textDir(value: TextDirective) {
|
|
|
|
this.setEvents.push('textDir set');
|
|
|
|
this._textDir = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@ContentChild('foo', {static: false})
|
|
|
|
get foo(): ElementRef { return this._foo; }
|
|
|
|
|
|
|
|
set foo(value: ElementRef) {
|
|
|
|
this.setEvents.push('foo set');
|
|
|
|
this._foo = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-18 21:18:56 -05:00
|
|
|
@Directive({selector: '[staticContentQueryDir]'})
|
|
|
|
class StaticContentQueryDir {
|
|
|
|
private _textDir !: TextDirective;
|
|
|
|
private _foo !: ElementRef;
|
|
|
|
setEvents: string[] = [];
|
|
|
|
|
|
|
|
@ContentChild(TextDirective, {static: true})
|
|
|
|
get textDir(): TextDirective { return this._textDir; }
|
|
|
|
|
|
|
|
set textDir(value: TextDirective) {
|
|
|
|
this.setEvents.push('textDir set');
|
|
|
|
this._textDir = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
@ContentChild('foo', {static: false})
|
|
|
|
get foo(): ElementRef { return this._foo; }
|
|
|
|
|
|
|
|
set foo(value: ElementRef) {
|
|
|
|
this.setEvents.push('foo set');
|
|
|
|
this._foo = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
feat(core): allow users to define timing of ViewChild/ContentChild queries (#28810)
Prior to this commit, the timing of `ViewChild`/`ContentChild` query
resolution depended on the results of each query. If any results
for a particular query were nested inside embedded views (e.g.
*ngIfs), that query would be resolved after change detection ran.
Otherwise, the query would be resolved as soon as nodes were created.
This inconsistency in resolution timing had the potential to cause
confusion because query results would sometimes be available in
ngOnInit, but sometimes wouldn't be available until ngAfterContentInit
or ngAfterViewInit. Code depending on a query result could suddenly
stop working as soon as an *ngIf or an *ngFor was added to the template.
With this commit, users can dictate when they want a particular
`ViewChild` or `ContentChild` query to be resolved with the `static`
flag. For example, one can mark a particular query as `static: false`
to ensure change detection always runs before its results are set:
```ts
@ContentChild('foo', {static: false}) foo !: ElementRef;
```
This means that even if there isn't a query result wrapped in an
*ngIf or an *ngFor now, adding one to the template later won't change
the timing of the query resolution and potentially break your component.
Similarly, if you know that your query needs to be resolved earlier
(e.g. you need results in an ngOnInit hook), you can mark it as
`static: true`.
```ts
@ViewChild(TemplateRef, {static: true}) foo !: TemplateRef;
```
Note: this means that your component will not support *ngIf results.
If you do not supply a `static` option when creating your `ViewChild` or
`ContentChild` query, the default query resolution timing will kick in.
Note: This new option only applies to `ViewChild` and `ContentChild`
queries, not `ViewChildren` or `ContentChildren` queries, as those types
already resolve after CD runs.
PR Close #28810
2019-02-18 17:38:14 -05:00
|
|
|
@Component({selector: 'subclass-static-content-query-comp', template: `<ng-content></ng-content>`})
|
|
|
|
class SubclassStaticContentQueryComp extends StaticContentQueryComp {
|
|
|
|
@ContentChild('bar', {static: true})
|
|
|
|
bar !: ElementRef;
|
|
|
|
|
|
|
|
@ContentChild('baz', {static: false})
|
|
|
|
baz !: ElementRef;
|
|
|
|
}
|
2019-02-18 20:33:59 -05:00
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'query-with-changes',
|
|
|
|
template: `
|
|
|
|
<div *ngIf="showing" #foo></div>
|
|
|
|
`
|
|
|
|
})
|
|
|
|
export class QueryCompWithChanges {
|
|
|
|
@ViewChildren('foo') foos !: QueryList<any>;
|
|
|
|
|
|
|
|
showing = false;
|
|
|
|
}
|
2019-03-13 14:30:38 -04:00
|
|
|
|
|
|
|
@Component({selector: 'query-target', template: '<ng-content></ng-content>'})
|
|
|
|
class SuperDirectiveQueryTarget {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Directive({selector: '[super-directive]'})
|
|
|
|
class SuperDirective {
|
|
|
|
@ViewChildren(SuperDirectiveQueryTarget) headers !: QueryList<SuperDirectiveQueryTarget>;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Component({
|
|
|
|
template: `
|
|
|
|
<query-target>One</query-target>
|
|
|
|
<query-target>Two</query-target>
|
|
|
|
`
|
|
|
|
})
|
|
|
|
class SubComponent extends SuperDirective {
|
|
|
|
}
|