import { Directive , ElementRef , EventEmitter , HostBinding , Input , OnDestroy , OnInit , Output , Renderer2 } from '@angular/core' ; import { Subject } from 'rxjs' ; import { takeUntil } from 'rxjs/operators' ; import { ResizeService } from '../resize/index' ; @ Directive ( { selector : '[uxFixedHeaderTable]' , exportAs : 'ux-fixed-header-table' } ) export class FixedHeaderTableDirective < T > implements OnInit , OnDestroy { /** Allow dataset changes to trigger re-layout */ @ Input ( ) set dataset ( _dataset ) { requestAnimationFrame ( ( ) => this . setLayout ( ) ) ; } /** Define the table height */ @ Input ( ) tableHeight : number | string ; /** Emit when the table tries to load more data */ @ Output ( ) tablePaging : EventEmitter < number > = new EventEmitter < number > ( ) ; /** Apply a class whenever the table has scrolled */ @ HostBinding ( 'class.ux-fixed-header-table-scrolled' ) _hasScrolled : boolean = false ; /** Store the table head element */ private _tableHead : HTMLTableSectionElement ; /** Store the table body element */ private _tableBody : HTMLTableSectionElement ; /** Unsubscribe from all observables on destroy */ private _onDestroy = new Subject < void > ( ) ; constructor ( private _elementRef , private _renderer , private _resizeService ) { } ngOnInit ( ) { this . _renderer . addClass ( this . _elementRef . nativeElement , 'ux-fixed-header-table' ) ; this . _tableHead = this . _elementRef . nativeElement . querySelector ( 'thead' ) as HTMLTableSectionElement ; this . _tableBody = this . _elementRef . nativeElement . querySelector ( 'tbody' ) as HTMLTableSectionElement ; this . _renderer . listen ( this . _tableBody , 'scroll' , this . onScroll . bind ( this ) ) ; this . setLayout ( ) ; this . _resizeService . addResizeListener ( this . _elementRef . nativeElement ) . pipe ( takeUntil ( this . _onDestroy ) ) . subscribe ( ( ) => this . setLayout ( ) ) ; this . tablePaging . emit ( ) ; } ngOnDestroy ( ) { this . _onDestroy . next ( ) ; this . _onDestroy . complete ( ) ; } /**
     * Get the table element
     * Primarily used by column width directive
     */ getTable ( ) { return this . _elementRef . nativeElement ; } /**
     * Update the size of the table header to account for the scrollbar.
     * This is important to keep the columns aligned
     */ setLayout ( ) { if ( ! this . _tableBody || ! this . _tableHead ) { return ; } const scrollbar = this . _tableBody . offsetWidth - this . _tableBody . clientWidth ; this . _renderer . setStyle ( this . _tableHead , 'padding-right' , scrollbar + 'px' ) ; this . _renderer . setStyle ( this . _tableBody , 'height' , typeof this . tableHeight === 'number' ? `${ this . tableHeight }px` : this . tableHeight ) ; } /**
     * Handle scroll events
     */ private onScroll ( ) { const scrollTop = this . _tableBody . scrollTop ; const scrollHeight = this . _tableBody . scrollHeight - this . _tableBody . offsetHeight ; const delta = Math . max ( scrollTop , scrollHeight ) - Math . min ( scrollTop , scrollHeight ) ; if ( delta < 1 ) { this . tablePaging . emit ( ) ; } this . _hasScrolled = ( scrollTop > 0 ) ; } }