First of all, as @JB Nizet has already mentioned in comments the comment in the issue is wrong: it has nothing to do with query selector but rather refers to directive selector.
Let's examine what kind of selectors we can use for queries.
Angular documentation states that for queries:
selector - the directive type or the name used for querying.
The directive type
Seems it should be clear for anyone that (1) we can query any classes adorned by @Component
or @Directive
decorator.
@Component({
selector: 'some-comp',
template: '...'
})
export class SomeComp {}
@Directive({
selector: '[someDir]'
})
export class SomeDir {}
@Component({
selector: 'host-comp',
template: `
<some-comp someDir></some-comp>
`
})
export class HostComp {
@ViewChild(SomeComp) someComp: SomeComp;
@ViewChild(SomeDir) someDir: SomeDir;
}
The name used for querying
As for me this is confusing description.
As it turned out the name here is (2) the name of template reference variable which is a string:
@Component({
selector: 'host-comp',
template: `
<some-comp #someComp></some-comp>
`
})
export class HostComp {
@ViewChild('someComp') someComp: SomeComp;
}
we could end up here but it's time to take a look at angular source code and dive a bit deeper.
Hidden behavior
Let's look at the code that angular compiler uses to read query metadata:
private _queryVarBindings(selector: any): string[] { return selector.split(/\s*,\s*/); }
private _getQueryMetadata(q: Query, propertyName: string, typeOrFunc: Type|Function):
cpl.CompileQueryMetadata {
let selectors: cpl.CompileTokenMetadata[];
if (typeof q.selector === 'string') {
selectors =
this._queryVarBindings(q.selector).map(varName => this._getTokenMetadata(varName));
} else {
if (!q.selector) {
this._reportError(
syntaxError(
`Can't construct a query for the property ...`),
typeOrFunc);
selectors = [];
} else {
selectors = [this._getTokenMetadata(q.selector)];
}
}
From the preceding code we can conclude that:
Let’s apply our learnings from above code.
We (3) can query several values by using several template reference variables divided by ,
:
@Component({
selector: 'a',
template: '...'
})
export class A {}
@Component({
selector: 'b',
template: '...'
})
export class B {}
@Component({
selector: 'host-comp',
template: `
<a #a></a>
<b #b></b>
`
})
export class HostComp {
@ViewChildren('a, b') components;
ngAfterViewInit() {
console.log(this.components); // [A, B]
}
}
(4) Provider defined on a component or directive can be queried. (see also example added by @Ilia Volk)
@Component({
selector: 'a',
template: '...',
providers: [SomeService]
})
export class A {}
@Component({
selector: 'host-comp',
template: `<a></a>`
})
export class HostComp {
@ViewChild(SomeService) someService: SomeService;
}
Since string can be a token for providers we can (5) query several providers that were defined through string token
@Component({
selector: 'a',
providers: [{ provide: 'tokenA', useValue: 'TokenAValue' }],
template: '...'
})
export class A { }
@Component({
selector: 'b',
providers: [{ provide: 'tokenB', useValue: 'TokenBValue' }],
template: '...'
})
export class B { }
@Component({
selector: 'host-comp',
template: `
<a #a></a>
<b #b></b>
`
})
export class HostComp {
@ViewChildren('tokenA, tokenB') stringTokenProviders;
ngAfterViewInit() {
console.log(this.stringTokenProviders); // ['TokenAValue', 'TokenBValue']
}
}
The next our stop is the place in core package where angular returns us the value of particular query:
export function getQueryValue(
view: ViewData, nodeDef: NodeDef, queryValueType: QueryValueType): any {
if (queryValueType != null) {
// a match
switch (queryValueType) {
case QueryValueType.RenderElement:
return asElementData(view, nodeDef.nodeIndex).renderElement;
case QueryValueType.ElementRef:
return new ElementRef(asElementData(view, nodeDef.nodeIndex).renderElement);
case QueryValueType.TemplateRef:
return asElementData(view, nodeDef.nodeIndex).template;
case QueryValueType.ViewContainerRef:
return asElementData(view, nodeDef.nodeIndex).viewContainer;
case QueryValueType.Provider:
return asProviderData(view, nodeDef.nodeIndex).instance;
}
}
}
RenderElement
in the code above is some internal token that we can't query.
ElementRef
can be queried through template reference variable or by using read option
(6) TemplateRef can be queried through selector
:
@Component({
selector: 'host-comp',
template: `
<ng-template></ng-template>
`
})
export class HostComp {
@ViewChild(TemplateRef) template;
}
and of course as well as ViewContainerRef
through read
option.
Provider
can be obtained by using read
option or through selector as I've described in the middle of this answer.
@Component
and@Directive
selectors, but not about@ViewChild
selectors. – Compact