import {NgModule,Component,ElementRef,AfterViewInit,AfterViewChecked,AfterContentInit,EventEmitter,OnDestroy,Input,Output,TemplateRef,ContentChildren,QueryList,Renderer2,ViewChild,ChangeDetectorRef} from '@angular/core'; import {DomHandler} from '../dom/domhandler'; import {SharedModule,PrimeTemplate} from '../common/shared'; import {CommonModule} from '@angular/common'; @Component({ selector: 'p-carousel', template: `
`, providers: [DomHandler] }) export class Carousel implements AfterViewChecked,AfterViewInit,OnDestroy{ @Input() numVisible: number = 3; @Input() firstVisible: number = 0; @Input() headerText: string; @Input() circular: boolean = false; @Input() breakpoint: number = 560; @Input() responsive: boolean = true; @Input() autoplayInterval: number = 0; @Input() effectDuration: any = '1s'; @Input() easing: string = 'ease-out'; @Input() pageLinks: number = 3; @Input() style: any; @Input() styleClass: string; @Output() onPage: EventEmitter = new EventEmitter(); @ContentChildren(PrimeTemplate) templates: QueryList; public _value: any[]; public itemTemplate: TemplateRef; public left: any = 0; public items: any; public columns: any; public page: number; public valuesChanged: any; public interval: any; public anchorPageLinks: any[]; public mobileDropdownOptions: any[]; public selectDropdownOptions: any[]; public shrinked: boolean; @ViewChild('container') containerViewChild: ElementRef; @ViewChild('viewport') viewportViewChild: ElementRef; @ViewChild('items') itemsViewChild: ElementRef; documentResponsiveListener: any; differ: any; constructor(public el: ElementRef, public domHandler: DomHandler, public renderer: Renderer2, public cd: ChangeDetectorRef) {} ngAfterContentInit() { this.templates.forEach((item) => { switch(item.getType()) { case 'item': this.itemTemplate = item.template; break; default: this.itemTemplate = item.template; break; } }); } @Input() get value(): any[] { return this._value; } set value(val:any[]) { this._value = val; this.handleDataChange(); } handleDataChange() { if(this.value && this.value.length) { if(this.value.length && this.firstVisible >= this.value.length) { this.setPage(this.totalPages - 1); } } else { this.setPage(0); } this.valuesChanged = true; } ngAfterViewChecked() { if(this.valuesChanged && this.containerViewChild.nativeElement.offsetParent) { this.render(); this.valuesChanged = false; } } ngAfterViewInit() { if(this.responsive) { this.documentResponsiveListener = this.renderer.listen('window', 'resize', (event) => { this.updateState(); }); } } updateLinks() { this.anchorPageLinks = []; for (let i = 0; i < this.totalPages; i++) { this.anchorPageLinks.push(i); } } updateDropdown() { this.selectDropdownOptions = []; for (let i = 0; i < this.totalPages; i++) { this.selectDropdownOptions.push(i); } } updateMobileDropdown() { this.mobileDropdownOptions = []; if(this.value && this.value.length) { for (let i = 0; i < this.value.length; i++) { this.mobileDropdownOptions.push(i); } } } render() { if(this.autoplayInterval) { this.stopAutoplay(); } this.items = this.domHandler.find(this.itemsViewChild.nativeElement, 'li'); this.calculateColumns(); this.calculateItemWidths(); if(!this.responsive) { this.containerViewChild.nativeElement.style.width = (this.domHandler.width(this.containerViewChild.nativeElement)) + 'px'; } if(this.autoplayInterval) { this.circular = true; this.startAutoplay(); } this.updateMobileDropdown(); this.updateLinks(); this.updateDropdown(); this.cd.detectChanges(); } calculateItemWidths () { let firstItem = (this.items && this.items.length) ? this.items[0] : null; if(firstItem) { for (let i = 0; i < this.items.length; i++) { this.items[i].style.width = ((this.domHandler.innerWidth(this.viewportViewChild.nativeElement) - (this.domHandler.getHorizontalMargin(firstItem) * this.columns)) / this.columns) + 'px'; } } } calculateColumns() { if(window.innerWidth <= this.breakpoint) { this.shrinked = true; this.columns = 1; } else { this.shrinked = false; this.columns = this.numVisible; } this.page = Math.floor(this.firstVisible / this.columns); } onNextNav() { let lastPage = (this.page === (this.totalPages - 1)); if(!lastPage) this.setPage(this.page + 1); else if(this.circular) this.setPage(0); } onPrevNav() { if(this.page !== 0) this.setPage(this.page - 1); else if(this.circular) this.setPage(this.totalPages - 1); } setPageWithLink(event, p: number) { this.setPage(p); event.preventDefault(); } setPage(p, enforce?: boolean) { if(p !== this.page || enforce) { this.page = p; this.left = (-1 * (this.domHandler.innerWidth(this.viewportViewChild.nativeElement) * this.page)); this.firstVisible = this.page * this.columns; this.onPage.emit({ page: this.page }); } } onDropdownChange(val: string) { this.setPage(parseInt(val)); } get displayPageLinks(): boolean { return (this.totalPages <= this.pageLinks && !this.shrinked); } get displayPageDropdown(): boolean { return (this.totalPages > this.pageLinks && !this.shrinked); } get totalPages(): number { return (this.value && this.value.length) ? Math.ceil(this.value.length / this.columns) : 0; } routerDisplay () { let win = window; if(win.innerWidth <= this.breakpoint) return true; else return false; } updateState() { let win = window; if(win.innerWidth <= this.breakpoint) { this.shrinked = true; this.columns = 1; } else if(this.shrinked) { this.shrinked = false; this.columns = this.numVisible; this.updateLinks(); this.updateDropdown(); } this.calculateItemWidths(); this.setPage(Math.floor(this.firstVisible / this.columns), true); } startAutoplay() { this.interval = setInterval(() => { if(this.page === (this.totalPages - 1)) this.setPage(0); else this.setPage(this.page + 1); }, this.autoplayInterval); } stopAutoplay() { clearInterval(this.interval); } ngOnDestroy() { if(this.documentResponsiveListener) { this.documentResponsiveListener(); } if(this.autoplayInterval) { this.stopAutoplay(); } } } @NgModule({ imports: [CommonModule,SharedModule], exports: [Carousel,SharedModule], declarations: [Carousel] }) export class CarouselModule { }