I want to use the same name of template reference variables for querying at @ViewChildren
.
selector - the directive type or the name used for querying.
read - read a different token from the queried elements.
But, I got a template parse error:
Reference "#abc" is defined several times
Sample:
import {AfterViewInit, Component, Directive, Input, QueryList, ViewChildren, ElementRef} from '@angular/core';
@Directive({selector: 'pane'})
export class Pane {
@Input() id: string;
}
@Directive({selector: 'pane1'})
export class Pane1 {
@Input() id: string;
}
@Component({
selector: 'app-root',
template: `
<span #abc id="1"></span>
<pane1 #abc id="2"></pane1>
<pane #abc id="3" *ngIf="shouldShow"></pane>
<button (click)="show()">Show 3</button>
<button (click)="hide()">Hide 3</button>
<div>panes: {{serializedPanes}}</div>
`,
})
export class ViewChildrenComp implements AfterViewInit {
@ViewChildren('abc') panes: QueryList<ElementRef>;
serializedPanes: string = '';
shouldShow = false;
show() { this.shouldShow = true; }
hide() { this.shouldShow = false; }
ngAfterViewInit() {
this.calculateSerializedPanes();
this.panes.changes.subscribe(
(r) => {
this.calculateSerializedPanes();
});
}
calculateSerializedPanes() {
setTimeout(
() => {
this.serializedPanes = this.panes.map(p => p.nativeElement.id).join(', ');
}, 0);
}
}
Question:
1. Whether I can define template reference variables with same name in template?
2. How to query multiple elements using the same selector, not defining names individually?
You can't define template reference variables with the same name in one template.
You can only define it in different templates including EmbeddedViewTemplate
, i.e.
<div #abc>
<ng-template #abc>
<ng-template>
<div #abc></div>
</ng-template>
</ng-template>
</div>
should work
or
<div #abc>
<ng-template #abc>
<div #abc></div>
</ng-template>
<ng-template #abc>
<div #abc></div>
</ng-template>
</div>
should also work
How to query multiple elements using the same selector, not defining names individually?
You can define directive like
@Directive({selector: '[id]'})
export class Abc {
constructor(public elRef: ElementRef) {}
}
Selector can be [abc]
then you need to add abc
attribute to all elements
<span abc id="1"></span>
<pane1 abc id="2"></pane1>
<pane abc id="3" *ngIf="shouldShow"></pane>
But since you have already defined id
i use it as selector
After that you can use Abc
directive mentioned above as selector for @ViewChildren
@ViewChildren(Abc) panes: QueryList<ElementRef>;
this.serializedPanes = this.panes.map(p => p.elRef.nativeElement.id).join(', ');
But there is some trick that can help us to have one variable several times. Just wrap your elements into another element i.e.
<div>
<span #abc id="1"></span>
<pane1 #abc id="2"></pane1>
<pane #abc id="3" *ngIf="shouldShow"></pane>
</div>
or
<ng-container>
<span #abc id="1"></span>
<pane1 #abc id="2"></pane1>
<pane #abc id="3" *ngIf="shouldShow"></pane>
</ng-container>