<!DOCTYPE html>
<html>
<head>
<title>angular2 playground</title>
<link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/2.0.0-beta.15/angular2-polyfills.js"></script>
<script src="https://code.angularjs.org/tools/system.js"></script>
<script src="https://code.angularjs.org/tools/typescript.js"></script>
<script src="config.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.15/Rx.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.15/angular2.dev.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.15/router.dev.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.15/http.dev.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</head>
<body>
<my-app>
loading...
</my-app>
</body>
</html>
.collapse {
display: none;
}
.collapse.in {
display: block;
}
.collapsing {
position: relative;
height: 0;
overflow: hidden;
-webkit-transition-timing-function: ease;
-o-transition-timing-function: ease;
-moz-transition-timing-function: ease;
transition-timing-function: ease;
-webkit-transition-duration: .35s;
-o-transition-duration: .35s;
-moz-transition-duration: .35s;
transition-duration: .35s;
-webkit-transition-property: height, visibility;
-o-transition-property: height, visibility;
-moz-transition-property: height, visibility;
transition-property: height, visibility;
}
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
//map tells the System loader where to look for things
map: {
app: "./src"
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
}
}
});
//main entry point
import {bootstrap} from 'angular2/platform/browser';
import {provide} from 'angular2/core';
import {AppComponent} from './app';
import {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router';
bootstrap(AppComponent, [ROUTER_PROVIDERS])
.catch(err => console.error(err));
//our root app component
import {Component, Directive, Renderer, HostListener, ViewChildren, ElementRef} from 'angular2/core'
import {Collapse} from './collapse.ts';
@Component({
selector: 'my-app',
directives: [Collapse],
template: `
<style>
.my-box {
border: 1px solid red;
padding: 10px;
background-color: lightgreen;
}
/* Add support for padding animation for smooth hide/show */
.collapsing {
-webkit-transition-property: height, visibility, padding;
-o-transition-property: height, visibility, padding;
transition-property: height, visibility, padding;
}
</style>
<h1>Native slide toggle / collapse for Angular 2 and Animate</h1>
<h2>Written as a demo for a <a target="_blank" href="http://blog.assaf.co/native-slide-toggle-for-angular-2-and-animate/">blog post</a> walkthrough.</h2>
<button (click)="collapsed = !collapsed">Toggle Collapse</button>
<div class="my-box" [collapse]="collapsed" [duration]="duration">
<h4>Native slide toggle / collapse for Angular 2 and Animate</h4>
<h4>Native slide toggle / collapse for Angular 2 and Animate</h4>
<h4>Native slide toggle / collapse for Angular 2 and Animate</h4>
<h4>Native slide toggle / collapse for Angular 2 and Animate</h4>
<h4>Native slide toggle / collapse for Angular 2 and Animate</h4>
<h4>Native slide toggle / collapse for Angular 2 and Animate</h4>
</div>
`,
})
export class AppComponent {
private collapsed: boolean = false;
// change this value to control animation duration.
private duration: number = 1000;
constructor() {
}
}
import {Directive, OnChanges, ElementRef, Input} from 'angular2/core';
import {AnimationBuilder} from 'angular2/src/animate/animation_builder';
import {CssAnimationBuilder} from 'angular2/src/animate/css_animation_builder';
@Directive({
selector: '[collapse]',
host: {
'[attr.aria-expanded]': '!collapse',
'[attr.aria-hidden]': 'collapse'
}
})
export class Collapse implements OnChanges {
@Input() duration: number = 500;
@Input() collapse: boolean;
private _animation: CssAnimationBuilder;
constructor(animationBuilder:AnimationBuilder, private _element:ElementRef) {
this._animation = animationBuilder.css();
}
ngOnChanges(changes) {
if (changes.collapse) {
if (this.collapse) {
this.hide()
} else {
this.show();
}
}
}
hide(): void {
this._baseSequence
.setFromStyles({
height: this._element.nativeElement.scrollHeight + 'px',
overflow: 'hidden'
})
.setToStyles({
height: '0',
paddingTop: '0',
paddingBottom: '0'
});
let a = this._animation.start(this._element.nativeElement);
a.onComplete(() => {
a.removeClasses(['in']); // rapid change will leave in
a.addClasses(['collapse']);
});
}
show(): void {
this._animation
.setDuration(0)
.addClass('in')
.setFromStyles({
overflow: 'hidden'
})
.setToStyles({
paddingTop: '',
paddingBottom: ''
})
.start(this._element.nativeElement)
.onComplete(() => {
let a = this._baseSequence
.setFromStyles({
height: '0'
})
.setToStyles({
height: this._element.nativeElement.scrollHeight + 'px'
})
.start(this._element.nativeElement);
a.onComplete(() => a.addClasses(['collapse', 'in']) );
});
}
private get _elementHeight(): number {
let el = this._element.nativeElement;
var height = el.offsetHeight;
var style = getComputedStyle(el);
height += parseInt(style.marginTop) + parseInt(style.marginBottom);
return height;
}
private get _baseSequence(): CssAnimationBuilder {
return this._animation
.setDuration(this.duration)
.removeClass('collapse')
.removeClass('in')
.addAnimationClass('collapsing')
}
}