How can I create simple accordion with Angular 2?

2019-07-26 06:23发布

Before, I use this simple script to create a simple accordion

(function() { 

    $('dl.accordion').on('click', 'dt', function() {
        this_= $(this);
        this_
            .addClass("selected")
            .next()
                .slideDown(200)
                .siblings('dd')
                    .slideUp(200);
        this_.siblings()
            .removeClass("selected")

    });
})();

And this html

<dl class="accordion">
    <dt>What are your hours?</dt>
    <dd>We are open 24/7.</dd>
    <dt>What are your hours?</dt>
    <dd>We are open 24/7.</dd>
</dl>

Now I want to create a copy of this code written in Angular 2.

How can I create a simple acordion like above in Angular 2?

I guess I have to learn renderer, elementRef etc. Could you suggest other topics which I should learn to create this?

3条回答
趁早两清
2楼-- · 2019-07-26 06:38

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:

查看更多
We Are One
3楼-- · 2019-07-26 06:42

The Problem

The biggest thing to take away is knowing the "GetElementbyClassName" or "GetElementbyID" will not work unless it is being called within Angular 2. This is because the DOM will always load before Angular components loads thus there will never be an object to get a class or id from.

Solution

Angular has "Hooks" that you can tap into that will allow you to run code when a specific event happens, such as when component loads ngAfterViewInit()

This can all be avoided by using directives to do your accordion but if you want to run your above javascript, then just run that in an ngAfterViewInit() function in your export class componentName {}and it will work.

Sample

Here is a sample where I did exactly what I stated above:

import { Component } from '@angular/core';

@Component({
  selector: 'events',
  templateUrl: "partials/events.html"
})
export class EventsComponent {
    ngAfterViewInit() {
        var acc = document.getElementsByClassName("accordion");
        var i;

for (i = 0; i < acc.length; i++) {
    acc[i].onclick = function(){
        this.classList.toggle("active");
        this.nextElementSibling.classList.toggle("show");
        }
    }
}

} // export class
查看更多
爷的心禁止访问
4楼-- · 2019-07-26 06:52

I don't know whether my solution is legal within angular, but I've come up with a simple accordion using a service.

Click here to check out solution on stackblitz

查看更多
登录 后发表回答