Skip to content

Commit

Permalink
fix(compiler): assume queries with no matches as static (#15429)
Browse files Browse the repository at this point in the history
This has the side effect of allowing `@Input` and `@ContentChild`
on the same property if the query is static (see the bug description
for details).

Fixes #15417
  • Loading branch information
tbosch authored and vicb committed Mar 23, 2017
1 parent 92084f2 commit c8ab5cb
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 15 deletions.
31 changes: 17 additions & 14 deletions packages/compiler/src/view_compiler/view_compiler.ts
Expand Up @@ -147,12 +147,8 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
// Note: queries start with id 1 so we can use the number in a Bloom filter!
const queryId = queryIndex + 1;
const bindingType = query.first ? QueryBindingType.First : QueryBindingType.All;
let flags = NodeFlags.TypeViewQuery;
if (queryIds.staticQueryIds.has(queryId)) {
flags |= NodeFlags.StaticQuery;
} else {
flags |= NodeFlags.DynamicQuery;
}
const flags =
NodeFlags.TypeViewQuery | calcStaticDynamicQueryFlags(queryIds, queryId, query.first);
this.nodes.push(() => ({
sourceSpan: null,
nodeFlags: flags,
Expand Down Expand Up @@ -491,15 +487,9 @@ class ViewBuilder implements TemplateAstVisitor, LocalResolver {
this.nodes.push(null);

dirAst.directive.queries.forEach((query, queryIndex) => {
let flags = NodeFlags.TypeContentQuery;
const queryId = dirAst.contentQueryStartId + queryIndex;
// Note: We only make queries static that query for a single item.
// This is because of backwards compatibility with the old view compiler...
if (queryIds.staticQueryIds.has(queryId) && query.first) {
flags |= NodeFlags.StaticQuery;
} else {
flags |= NodeFlags.DynamicQuery;
}
const flags =
NodeFlags.TypeContentQuery | calcStaticDynamicQueryFlags(queryIds, queryId, query.first);
const bindingType = query.first ? QueryBindingType.First : QueryBindingType.All;
this.nodes.push(() => ({
sourceSpan: dirAst.sourceSpan,
Expand Down Expand Up @@ -1194,3 +1184,16 @@ function elementEventNameAndTarget(
return eventAst;
}
}

function calcStaticDynamicQueryFlags(
queryIds: StaticAndDynamicQueryIds, queryId: number, isFirst: boolean) {
let flags = NodeFlags.None;
// Note: We only make queries static that query for a single item.
// This is because of backwards compatibility with the old view compiler...
if (isFirst && (queryIds.staticQueryIds.has(queryId) || !queryIds.dynamicQueryIds.has(queryId))) {
flags |= NodeFlags.StaticQuery;
} else {
flags |= NodeFlags.DynamicQuery;
}
return flags;
}
31 changes: 30 additions & 1 deletion packages/core/test/linker/regression_integration_spec.ts
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, Directive, InjectionToken, Injector, Input, Pipe, PipeTransform, Provider, QueryList, Renderer2, SimpleChanges, TemplateRef, ViewChildren, ViewContainerRef} from '@angular/core';
import {ANALYZE_FOR_ENTRY_COMPONENTS, Component, ContentChild, Directive, InjectionToken, Injector, Input, Pipe, PipeTransform, Provider, QueryList, Renderer2, SimpleChanges, TemplateRef, ViewChildren, ViewContainerRef} from '@angular/core';
import {TestBed, fakeAsync, tick} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers';
Expand Down Expand Up @@ -336,6 +336,35 @@ function declareTests({useJit}: {useJit: boolean}) {
expect(fixture.debugElement.childNodes.length).toBe(2);
});
});

it('should support @ContentChild and @Input on the same property for static queries', () => {
@Directive({selector: 'test'})
class Test {
@Input() @ContentChild(TemplateRef) tpl: TemplateRef<any>;
}

@Component({
selector: 'my-app',
template: `
<test></test><br>
<test><ng-template>Custom as a child</ng-template></test><br>
<ng-template #custom>Custom as a binding</ng-template>
<test [tpl]="custom"></test><br>
`
})
class App {
}

const fixture =
TestBed.configureTestingModule({declarations: [App, Test]}).createComponent(App);
fixture.detectChanges();

const testDirs =
fixture.debugElement.queryAll(By.directive(Test)).map(el => el.injector.get(Test));
expect(testDirs[0].tpl).toBeUndefined();
expect(testDirs[1].tpl).toBeDefined();
expect(testDirs[2].tpl).toBeDefined();
});
});
}

Expand Down

0 comments on commit c8ab5cb

Please sign in to comment.