AbhiRam
AbhiRam

Reputation: 2061

How to do Accordions in Angular

I am a beginner for angular and I am trying to Accordions using below code but it's not working and showing error like event.getElementsByClassName is not a function can someone help me please where did I do wrong

.html:

h2>Accordion</h2>

<button class="accordion" (click) = "expand($event)">Section 1</button>
<div class="panel">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>

<button class="accordion" (click) = "expand($event)">Section 2</button>
<div class="panel">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>

<button class="accordion" (click) = "expand($event)">Section 3</button>
<div class="panel">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>

.css:

.accordion {
    background-color: #eee;
    color: #444;
    cursor: pointer;
    padding: 18px;
    width: 100%;
    border: none;
    text-align: left;
    outline: none;
    font-size: 15px;
    transition: 0.4s;
}

.active, .accordion:hover {
    background-color: #ccc; 
}

.panel {
    padding: 0 18px;
    display: none;
    background-color: white;
    overflow: hidden;
}

.ts:

export class HomePage {

  expand(event){

         var panel = event.getElementsByClassName("accordion");
         if (panel.style.display === "block") {
           panel.style.display = "none";
       } else {
             panel.style.display = "block";
        }  

    }
}

Upvotes: 1

Views: 3911

Answers (3)

SiddAjmera
SiddAjmera

Reputation: 39482

If you have a dynamic list that you'd get from some API and then you want to render that in the accordion, you can create a CSS class(visible say) to apply a display: block

Then, create a property(currentIndex) in your Component Class. Whenever you click on a section, just set the currentIndex to the index of the section that was clicked. And based on the currentIndex, apply the visible CSS class via [ngClass]

Template:

<h2>Accordion</h2>

<div *ngFor="let section of sections; let i = index;">
  <button class="accordion" (click) = "expand(i)">{{section.name}}</button>
  <div class="panel"
    [ngClass]="{ 'visible' : currentIndex === i }">
    <p>{{section.content}}</p>
  </div>
</div>

Class:

export class HomePage {
  currentIndex = -1;

  sections = [
    { name: 'Section 1', content: 'Content 1' },
    { name: 'Section 2', content: 'Content 2' },
    { name: 'Section 3', content: 'Content 3' },
    ...
  ];

  expand(index) {
    if(this.currentIndex === index) {
      this.currentIndex = null;
      return;
    }
    this.currentIndex = index;
  }

}

CSS:

...

.visible {
  display: block;
}

Here's a StackBlitz for your ref.

Upvotes: 0

user4676340
user4676340

Reputation:

Although you have the good idea, you should stop using "old ways".

Angular is a framework with very powerful features. If you don't take advantage of them to their full extent, then you should not use it !

For instance look at this stackblitz : although very minimal, it shows the power of Angular. No code in the component, and you already have an (non-animated) accordion !

<div class="accordion">
  <h2 class="title" (click)="opened = !opened">Title of the accordion</h2>
  <div class="content-container" [class.opened]="opened">
    <p class="content">Content of the accordion</p>
  </div>
</div>

I would suggest you to read the documentation so that you see everything Angular can do. I know it's long, but trust me, it's worth it.

Upvotes: 2

SeleM
SeleM

Reputation: 9678

Change your Ts function to:

 expand(event){
     if (event.style.display === "block") {
       event.style.display = "none";
   } else {
         event.style.display = "block";
    }  
}

And your HTML part should be:

    <h2>Accordion</h2>

<button class="accordion" (click) = "expand(panel1)">Section 1</button>
<div #panel1 class="panel">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>

<button class="accordion" (click) = "expand(panel2)">Section 2</button>
<div #panel2 class="panel">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>

<button class="accordion" (click) = "expand(panel3)">Section 3</button>
<div #panel3 class="panel">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>

Here a working stackblitz

PS: You can reach the same result in various different ways.

Upvotes: 1

Related Questions