feat(query): allow to query for `TemplateRef`

Part of #1989

Closes #3202
This commit is contained in:
Tobias Bosch 2015-07-22 14:24:57 -07:00
parent 5b5d31fa9a
commit 585ea5d600
5 changed files with 61 additions and 6 deletions

View File

@ -714,6 +714,10 @@ export class ElementInjector extends TreeNode<ElementInjector> implements Depend
} }
addDirectivesMatchingQuery(query: Query, list: any[]): void { addDirectivesMatchingQuery(query: Query, list: any[]): void {
var templateRef = this._preBuiltObjects.templateRef;
if (query.selector === TemplateRef && isPresent(templateRef)) {
list.push(templateRef);
}
this._strategy.addDirectivesMatchingQuery(query, list); this._strategy.addDirectivesMatchingQuery(query, list);
} }

View File

@ -366,10 +366,13 @@ function _createProtoElementInjector(binderIndex, parentPeiWithDistance, renderE
componentDirectiveBinding, directiveBindings) { componentDirectiveBinding, directiveBindings) {
var protoElementInjector = null; var protoElementInjector = null;
// Create a protoElementInjector for any element that either has bindings *or* has one // Create a protoElementInjector for any element that either has bindings *or* has one
// or more var- defined. Elements with a var- defined need a their own element injector // or more var- defined *or* for <template> elements:
// so that, when hydrating, $implicit can be set to the element. // - Elements with a var- defined need a their own element injector
// so that, when hydrating, $implicit can be set to the element.
// - <template> elements need their own ElementInjector so that we can query their TemplateRef
var hasVariables = MapWrapper.size(renderElementBinder.variableBindings) > 0; var hasVariables = MapWrapper.size(renderElementBinder.variableBindings) > 0;
if (directiveBindings.length > 0 || hasVariables) { if (directiveBindings.length > 0 || hasVariables ||
isPresent(renderElementBinder.nestedProtoView)) {
var directiveVariableBindings = var directiveVariableBindings =
createDirectiveVariableBindings(renderElementBinder, directiveBindings); createDirectiveVariableBindings(renderElementBinder, directiveBindings);
protoElementInjector = protoElementInjector =

View File

@ -28,5 +28,5 @@ export class TemplateRef {
/** /**
* Whether this template has a local variable with the given name * Whether this template has a local variable with the given name
*/ */
hasLocal(name: string): boolean { return this._getProtoView().protoLocals.has(name); } hasLocal(name: string): boolean { return this._getProtoView().variableBindings.has(name); }
} }

View File

@ -166,6 +166,12 @@ class NeedsQueryByVarBindings {
constructor(@Query("one,two") query: QueryList<any>) { this.query = query; } constructor(@Query("one,two") query: QueryList<any>) { this.query = query; }
} }
@Injectable()
class NeedsTemplateRefQuery {
query: QueryList<TemplateRef>;
constructor(@Query(TemplateRef) query: QueryList<TemplateRef>) { this.query = query; }
}
@Injectable() @Injectable()
class NeedsElementRef { class NeedsElementRef {
elementRef; elementRef;
@ -1009,6 +1015,16 @@ export function main() {
expectDirectives(inj.get(NeedsQuery).query, CountingDirective, [0]); expectDirectives(inj.get(NeedsQuery).query, CountingDirective, [0]);
}) })
it('should contain PreBuiltObjects on the same injector', () => {
var preBuiltObjects = new PreBuiltObjects(null, null, null, new TemplateRef(<any>new DummyElementRef()));
var inj = injector(ListWrapper.concat([
NeedsTemplateRefQuery
], extraBindings), null,
false, preBuiltObjects);
expect(inj.get(NeedsTemplateRefQuery).query.first).toBe(preBuiltObjects.templateRef);
});
it('should contain multiple directives from the same injector', () => { it('should contain multiple directives from the same injector', () => {
var inj = injector(ListWrapper.concat([ var inj = injector(ListWrapper.concat([
NeedsQuery, NeedsQuery,

View File

@ -10,12 +10,13 @@ import {
it, it,
xit, xit,
TestComponentBuilder, TestComponentBuilder,
asNativeElements asNativeElements,
By
} from 'angular2/test_lib'; } from 'angular2/test_lib';
import {Injectable, Optional} from 'angular2/di'; import {Injectable, Optional} from 'angular2/di';
import {QueryList} from 'angular2/core'; import {QueryList, TemplateRef} from 'angular2/core';
import {Query, ViewQuery, Component, Directive, View} from 'angular2/annotations'; import {Query, ViewQuery, Component, Directive, View} from 'angular2/annotations';
import {NgIf, NgFor} from 'angular2/angular2'; import {NgIf, NgFor} from 'angular2/angular2';
@ -126,6 +127,24 @@ export function main() {
})); }));
}); });
describe('query for TemplateRef', () => {
it('should find TemplateRefs in the light and shadow dom',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<needs-tpl><template var-x="light"></template></needs-tpl>';
tcb.overrideTemplate(MyComp, template)
.createAsync(MyComp)
.then((view) => {
view.detectChanges();
var needsTpl: NeedsTpl = view.componentViewChildren[0].inject(NeedsTpl);
expect(needsTpl.query.first.hasLocal('light')).toBe(true);
expect(needsTpl.viewQuery.first.hasLocal('shadow')).toBe(true);
async.done();
});
}));
});
describe("onChange", () => { describe("onChange", () => {
it('should notify query on change', it('should notify query on change',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
@ -545,6 +564,18 @@ class NeedsViewQueryOrder {
constructor(@ViewQuery(TextDirective) query: QueryList<TextDirective>) { this.query = query; } constructor(@ViewQuery(TextDirective) query: QueryList<TextDirective>) { this.query = query; }
} }
@Component({selector: 'needs-tpl'})
@View({template: '<template var-x="shadow"></template>'})
class NeedsTpl {
viewQuery: QueryList<TemplateRef>;
query: QueryList<TemplateRef>;
constructor(@ViewQuery(TemplateRef) viewQuery: QueryList<TemplateRef>,
@Query(TemplateRef) query: QueryList<TemplateRef>) {
this.viewQuery = viewQuery;
this.query = query;
}
}
@Component({selector: 'my-comp'}) @Component({selector: 'my-comp'})
@View({ @View({
directives: [ directives: [
@ -558,6 +589,7 @@ class NeedsViewQueryOrder {
NeedsViewQueryIf, NeedsViewQueryIf,
NeedsViewQueryNestedIf, NeedsViewQueryNestedIf,
NeedsViewQueryOrder, NeedsViewQueryOrder,
NeedsTpl,
TextDirective, TextDirective,
InertDirective, InertDirective,
NgIf, NgIf,