Search code examples
angularbootstrap-5accordionng-bootstrap

ngbAccordion [closeOthers] attribute with *ngFor


I am creating an accordion list with the ngbAccordion directive. But I can't figure out how to make the [closeOthers] attribute work with *ngFor.

Setting this attribute to true is supposed to close items, when one is opened, so that only one item is open at a time. It works fine in a non-dynamic accordion.

I suspect it has to do with the naming of the elements. But AFAIK it isn't possible to dynamically generate #myItem1, #myItem2?

<div ngbAccordion #myAccordion="ngbAccordion" [closeOthers]="true" *ngFor="let item of items;let idx = index">
  <div ngbAccordionItem="myItem" #myItem="ngbAccordionItem" [collapsed]="true" >
      ... other stuff here...
  </div>
</div>

I have a Stackblitz here with a working and non-working example.

The Stackblitz example differs a bit from the versions I use in my project, but the trouble is the same:

  • Angular: 17.3
  • Bootstrap: 5.3
  • ng-bootstrap: 16.0

I am probably just doing it wrong, but I searched high and low.


Solution

  • Issue 1: You are creating four ngbAccordion elements as you place *ngFor in the ngbAccordion element.

    Solution: The *ngFor should be as the child in the ngbAccordion element.

    Issue 2: The id for ngbAccordionItem must be unique to make expand and collapse functions work.

    Solution: Generate the unique id with ngbAccordionItem="{{'panel' + (idx + 1) }}"

    Your ngbAccordion with supported dynamic content should be as below:

    <div ngbAccordion #myAccordion="ngbAccordion" [closeOthers]="true">
      <ng-container *ngFor="let item of items;let idx = index">
        <div
          ngbAccordionItem="{{'panel' + (idx + 1) }}"
          #first="ngbAccordionItem"
          [collapsed]="true"
        >
          <div
            ngbAccordionHeader
            class="accordion-button custom-header justify-content-between"
          >
            <p class="m-0">
              Panel {{item}} - {{ first.collapsed ? 'collapsed' : 'opened' }}
            </p>
            <button ngbAccordionToggle class="btn btn-link p-0">Toggle me</button>
          </div>
          <div ngbAccordionCollapse>
            <div ngbAccordionBody>
              <ng-template>
                Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus
                terry richardson ad squid. 3 wolf moon officia aute, non cupidatat
                skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod.
                Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid
                single-origin coffee nulla assumenda shoreditch et. Nihil anim
                keffiyeh helvetica, craft beer labore wes anderson cred nesciunt
                sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings
                occaecat craft beer farm-to-table, raw denim aesthetic synth
                nesciunt you probably haven't heard of them accusamus labore
                sustainable VHS.
              </ng-template>
            </div>
          </div>
        </div>
      </ng-container>
    </div>
    

    Demo @ StackBlitz