问题
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?
回答1:
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:
- EventEmitter
- @ContentChildren
- QueryList
回答2:
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
回答3:
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
来源:https://stackoverflow.com/questions/42113446/how-can-i-create-simple-accordion-with-angular-2