I'm facing an issue using ng bootstrap's accordion with components inside them.
I have an *ngFor
and for each index array there is an accordion that contains a component.
The problem is, even accordions at DOM rendering are closed all components inside accordion starting their life-cycle causing https calls for each component inside each accordion.
By default i left the accordion property destroyOnHide
(property of ngbAccordion) set as true but nothing.
Did someone face this problem?
Below HTML code component settings-tab.component.html
div
class="mt-2"
#accordion="ngbAccordion"
ngbAccordion
[closeOthers]="true"
(shown)="lastAccordionOpened = $event"
>
<div
ngbAccordionItem
*ngFor="let room of rooms; let index = index"
[ngbAccordionItem]="index.toString()"
>
<div ngbAccordionHeader>
<button
ngbAccordionButton
[style.backgroundColor]="room.bgColorHex"
[style.color]="room.textColorHex"
>
{{ room.name }}
</button>
</div>
<div ngbAccordionCollapse>
<div ngbAccordionBody>
<app-room-settings
[room]="room"
(roomChanged)="roomChanged.emit()"
></app-room-settings>
</div>
</div>
</div>
</div>
HTTP calls are made inside and if I set a console.log inside the constructor there are as many console.logs as the length of the array of rooms
The problem was that the accordion body content must be wrapped in an ng-template
since this was not done, the content is getting rendered even when the accordion is not open.
The same method can be found in the Official Doc Examples
First set destroyOnHide
to false
so that the components are destroyed.
Then you need to add trackBy
so that ngFor
knows which elements has changed, if not it will rerender all components.
<div
class="mt-2"
[destroyOnHide]="false"
#accordion="ngbAccordion"
ngbAccordion
[closeOthers]="true"
(shown)="lastAccordionOpened = $event"
>
<div
ngbAccordionItem
*ngFor="let room of rooms; trackBy: trackByFn;let index = index"
[ngbAccordionItem]="index.toString()"
>
<div ngbAccordionHeader>
<button
ngbAccordionButton
[style.backgroundColor]="room.bgColorHex"
[style.color]="room.textColorHex"
>
{{ room.name }}
</button>
</div>
<div ngbAccordionCollapse>
<div ngbAccordionBody>
<ng-template>
<app-room-settings
[room]="room"
(roomChanged)="roomChanged.emit()"
></app-room-settings>
</ng-template>
</div>
</div>
</div>
</div>
...
identify(index: number, item: any){
return item.id;
}
...
You have to supply and unique ID for each element, if there is no such index, you can either generate an ID, or just return the index.