goodoldneon777
goodoldneon777

Reputation: 147

ng-bootstrap: accordion reinitializes component

I'm using ngb-accordion in ng-bootstrap. Toggling a header causes its child components to reinitialize. For example, toggling headers cause dropdowns to reset. It looks like this is because <div class="card-block"></div> is deleted when the panel is hidden.

How do I maintain the state of components even when they're "hidden" in the accordion?

Template file:

<ngb-accordion activeIds="side-bar-accordion-1" (panelChange)="beforeChange($event)">

  <div [class.hide-card-block]="status">
  <ngb-panel id="side-bar-accordion-1" class="foo">
    <template ngbPanelTitle>
        <div class="title">Axes</div>
    </template>
    <template ngbPanelContent>
        <!--This is the component whose state I want to maintain:-->
        <side-bar-axes></side-bar-axes>
    </template>
  </ngb-panel>
  </div>

  <ngb-panel id="side-bar-accordion-2">
    <template ngbPanelTitle>
      <div class="title">Fancy</div>
    </template>
    <template ngbPanelContent>
      blah blah
    </template>
  </ngb-panel>

  <ngb-panel id="side-bar-accordion-3">
    <template ngbPanelTitle>
        <div class="title">Settings</div>
    </template>
    <template ngbPanelContent>
      blah blah
    </template>
  </ngb-panel>

</ngb-accordion>

Component TypeScript file:

import { Component, ViewChildren, ViewEncapsulation } from '@angular/core';
import { NgbPanelChangeEvent } from '@ng-bootstrap/ng-bootstrap';

import { FieldChooseFiltersComponent } from '../field-choose-filters/field-choose-filters.component';

@Component({
  moduleId: module.id,
    selector: 'side-bar',
    templateUrl: 'side-bar.component.html',
    styleUrls: ['side-bar.component.css'],
  encapsulation: ViewEncapsulation.None
})

export class SideBarComponent {
  hideNum: number = 1;
  status: boolean = false;

  toggleStatus() {
    this.status = !this.status;
  }
  public beforeChange($event: NgbPanelChangeEvent) {

    if ($event.panelId === '1' && $event.nextState === false) {
      $event.preventDefault();
    }

    if ($event.panelId === '2' && $event.nextState === false) {
      $event.preventDefault();
    }

    if ($event.panelId === '3' && $event.nextState === false) {
      $event.preventDefault();
    }
  };
}

Upvotes: 2

Views: 5947

Answers (2)

Andris
Andris

Reputation: 4203

NgbAccordion has input option destroyOnHide. It needs to be false. Take a look in docs here. Example: <ngb-accordion [destroyOnHide]="false">

Upvotes: 7

pkozlowski.opensource
pkozlowski.opensource

Reputation: 117370

The current implementation of https://ng-bootstrap.github.io/#/components/accordion assumes that only active (visible) panels shell be kept in the DOM. This was a conscious design decision as keeping non-visible panels around would mean that:

  • their content gets initialised even if never shown
  • Angular would have to run change detection on parts that are no visible and don't add to the experience to the end users.

So, currently things work as designed. If you want to preserve state when a panel gets opened / closed one option would be to move relevant state to one of a parent components.

If there is enough interest in the community we might add an option to not destroy panels' content when those are closed.

Upvotes: 3

Related Questions