Collapsible accordion in angular

28,876

Solution 1

Keep your function in ngAfterViewInit instead of ngOnInit. See updated stackblitz

The problem is that on ngOnInit the view is not completely painted, and you do not get all the elements on which you want to bind the function.

ngAfterViewInit() {
    var acc = document.getElementsByClassName("accordion");
    var i;

    for (i = 0; i < acc.length; i++) {
      acc[i].addEventListener("click", function () {
        this.classList.toggle("active");
        var panel = this.nextElementSibling;
        if (panel.style.maxHeight) {
          panel.style.maxHeight = null;
        } else {
          panel.style.maxHeight = panel.scrollHeight + "px";
        }
      });
    }
  }

Using angular do it like shown below.

Keep a click function on the button and bind a property isActive to the corresponding array element. Then show/hide the accordian based on if isActive has value true/false.

<div *ngFor="let item of data;let i = index;">
  <button class="accordion" (click)="toggleAccordian($event, i)"> {{item.parentName}} </button>
  <div class="panel" *ngFor="let child of item.childProperties" hide="!item.isActive">
  <p> {{child.propertyName}} </p>
</div>
</div>


toggleAccordian(event, index) {
      var element = event.target;
      element.classList.toggle("active");
      if(this.data[index].isActive) {
        this.data[index].isActive = false;
      } else {
        this.data[index].isActive = true;
      }      
      var panel = element.nextElementSibling;
      if (panel.style.maxHeight) {
        panel.style.maxHeight = null;
      } else {
        panel.style.maxHeight = panel.scrollHeight + "px";
      }
  }

Solution 2

The Stackblitz update only show the first element in childProperties Item so if u apply the *ngFor on the p tag you will get all the elements of childProperties

<p *ngFor="let child of item.childProperties"> {{child.propertyName}} </p>
Share:
28,876
Maniraj Murugan
Author by

Maniraj Murugan

Proud | 27 | Farmer | Cricketer Born and brought up from evergreen town Karur, Tamilnadu, India. Civil Engineer by graduation and Software Engineer by Profession .. If my answers helped you, feel free to buy a coffee for me You can contact me via email in [email protected] ..

Updated on May 14, 2020

Comments

  • Maniraj Murugan
    Maniraj Murugan about 4 years

    I am making accordion to make a collapsible div using javascript in angular application..

    For which if its not getting open on click over the button on Parent One or any other parent name..

    Html:

    <div *ngFor="let item of data">
      <button class="accordion"> {{item.parentName}} </button>
      <div class="panel" *ngFor="let child of item.childProperties">
      <p> {{child.propertyName}} </p>
    </div>
    </div>
    

    Ts:

    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
    
      data: any =
        [
          {
            "parentName": "Parent One",
            "childProperties":
              [
                { "propertyName": "Property One" },
                { "propertyName": "Property Two" }
              ]
          },
          {
            "parentName": "Parent Two",
            "childProperties":
              [
                { "propertyName": "Property Three" },
                { "propertyName": "Property Four" },
                { "propertyName": "Property Five" },
              ]
          },
          {
            "parentName": "Parent Three",
            "childProperties":
              [
                { "propertyName": "Property Six" },
                { "propertyName": "Property Seven" },
                { "propertyName": "Property Eight" },
              ]
          }
        ]
    
      ngOnInit() {
        var acc = document.getElementsByClassName("accordion");
        var i;
    
        for (i = 0; i < acc.length; i++) {
          acc[i].addEventListener("click", function () {
            this.classList.toggle("active");
            var panel = this.nextElementSibling;
            if (panel.style.maxHeight) {
              panel.style.maxHeight = null;
            } else {
              panel.style.maxHeight = panel.scrollHeight + "px";
            }
          });
        }
      }
    
    }
    

    Note: As i am new in angular i am making it with javascript way.. So kindly help me to achieve the result using pure angular and typescript..

    Working stackblitz https://stackblitz.com/edit/angular-lp3riw

    You can see in demo that the parent button are visible but if you click over the button its not getting expanded..

    Also listed down working collapsible button below with static values..

    How to make a collapsible accordion as like given stackblitz static values using angular and typescript way (Without any third party or jquery)..

  • Maniraj Murugan
    Maniraj Murugan over 5 years
    Thanks, But can you give the solution in angular typescript way, As i have already mentioned in the question which is important part..
  • Nandita Sharma
    Nandita Sharma over 5 years
    See the updated stackblitz.com/edit/…