try this solution, this is very simple accordion:
app/accordion.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'tp-accordion', template: ` <h2 class="accordion-head" (click)="onClick($event)">{{ title }}</h2> <div class="accordion-body" [class.active]="active"> <ng-content></ng-content> </div> `, styles: [ ` .accordion-head { cursor: pointer; } .accordion-body { display: none; } .accordion-body.active { display: block; -webkit-animation: fadeIn .3s; animation: fadeIn .3s; } @-webkit-keyframes fadeIn { from { opacity: 0; transform: scale(0); } to { opacity: 1; transform: scale(1); } } @keyframes fadeIn { from { opacity: 0; transform: scale(0); } to { opacity: 1; transform: scale(1); } } ` ], }) export class Accordion { @Input() title: string; @Input() active: boolean = false; @Output() toggleAccordion: EventEmitter<boolean> = new EventEmitter(); constructor() {} onClick(event) { event.preventDefault(); this.toggleAccordion.emit(this.active); } }
app/accordion-group.component.ts
import { Component, ContentChildren, QueryList, AfterContentInit, OnDestroy } from '@angular/core'; import { Accordion } from './accordion.component'; @Component({ selector: 'tp-accordion-group', template: ` <ng-content></ng-content> ` }) export class AccordionGroup { @ContentChildren(Accordion) accordions: QueryList<Accordion>; private subscriptions = []; private _accordions = []; constructor() {} ngAfterContentInit() { this._accordions = this.accordions; this.removeSubscriptions(); this.addSubscriptions(); this.accordions.changes.subscribe(rex => { this._accordions = rex; this.removeSubscriptions(); this.addSubscriptions(); }); } addSubscriptions() { this._accordions.forEach(a => { let subscription = a.toggleAccordion.subscribe(e => { this.toogleAccordion(a); }); this.subscriptions.push(subscription); }); } removeSubscriptions() { this.subscriptions.forEach(sub => { sub.unsubscribe(); }); } toogleAccordion(accordion) { if (!accordion.active) { this.accordions.forEach(a => a.active = false); } // set active accordion accordion.active = !accordion.active; } ngOnDestroy() { this.removeSubscriptions(); } }
app/app.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core'; import { PostsService } from './posts.service'; @Component({ selector: 'app-root', template: ` <tp-accordion-group> <tp-accordion *ngFor="let post of posts" [title]="post.title"> {{ post.body }} </tp-accordion> </tp-accordion-group> ` }) export class AppComponent implements OnInit, OnDestroy { posts = []; private subscription: any; constructor(private postsSvc: PostsService) {} ngOnInit() { this.subscription = this.postsSvc.getPosts().subscribe(res => { if (res.length) { this.posts = res.slice(0, 10); } }) } ngOnDestroy() { if (this.subscription) { this.subscription.unsubscribe(); } } }
app/posts.service.ts
import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/map'; import 'rxjs/add/operator/catch'; @Injectable() export class PostsService { postsUrl: 'https://jsonplaceholder.typicode.com/posts'; constructor(private http: Http) { } getPosts() { return this.http.get(this.postsUrl) .map(res => { let body = res.json(); return body || []; }) .catch(console.log); } }
Online demo: https://plnkr.co/edit/xFBllK?p=preview
Document: