I am working on an angular 6 application which uses dynamic components. I am using @ViewChild('<id>', { read: ViewContainerRef }) <id>; in order to refer to the divs I would populate with dynamic components. The ViewContainerRef looks for a # tag with an id to identify which item it refers to in the template.
I have created an accordion within which I want to dynamically add a specific reusable component, which I have been doing throughout the rest of the application by the process mentioned above. However, since there are many tabs in an accordion I want to add a loop using *ngFor that would do the job for me, where I set the #id using a value specified in the loop. I implemented the following template:
<app-create-feature-modal></app-create-feature-modal>
<app-button description="{{ 'pages[knowledge_base][buttons][accordion_add]' | translate }}" class="btn btn-primary btn-md accordion-button" (callFunction)="add()"></app-button>
<div class="acc">
<div *ngFor="let item of meta; let i = index">
<button class="accordion" (click)="toggle(i)">{{item.name}}</button>
<div class="{{'panel panel-'+ i}}">
<div #{{item.value}}></div> <!--here-->
</div>
</div>
</div>
However, on running the application, the id is not properly set and on inspecting the console I see that the reference to @ViewChild is undefined, and even within the html there are no id's defined, just plain divs.
I cannot use id="{{item.value}}" because the ViewContainerRef does not recognize it, which is why this solution would not work for me.
Is there any possible way I can achieve this?
You would use [attr.id]="item.value".
<div [attr.id]="item.value"></div>
Update
The idea of give "id" to a tag if when we want to use plain javaScript and get the html element using
const el=document.getElementById(..)
But in Angular we should avoid use it. In Angular we have the "template reference variable. A simple #element. When is under a *ngFor generally we have no problem to use the same. If we use in the own html the "scope" avoid problems, so, e.g.
<div *ngFor="let item of meta; let i = index">
<button class="accordion" (click)="toggle(item)">
{{item.name}}
</button>
<div #element>Hello</div>
</div>
//code
toggle(el:HTMLElement)
{
el.classList.toggle("mystyle");
}
See that when use in .html we get the HTMLElement or, if the reference variable is a component, the own component.
When we get in code we use ViewChildren
@ViewChildren('element') elements!:QueryList<ElementRef>
And we neend't pass the "element", so we can use
toogle(index:number)
{
const el=elements.find((_,i:number)=>i==index)
if (el)
el.nativeElement.classList.toggle("mystyle");
}
See that in this case we get the "ElementRef", so we need use el.nativeElement
a stackblitz with this ideas
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With