import { Component , Input , Output , EventEmitter , ContentChildren , QueryList , TemplateRef , ContentChild , ViewChildren , OnInit } from '@angular/core' ; import { DataTableColumn } from './column.component' ; import { DataTableRow } from './row.component' ; import { DataTableParams } from './types' ; import { RowCallback } from './types' ; import { DataTableTranslations , defaultTranslations } from './types' ; import { drag } from '../utils/drag' ; import { TABLE_TEMPLATE } from './table.template' ; import { TABLE_STYLE } from "./table.style" ; @ Component ( { selector : 'data-table' , template : TABLE_TEMPLATE , styles : [ TABLE_STYLE ] } ) export class DataTable implements DataTableParams , OnInit { private _items : any [ ] = [ ] ; @ Input ( ) get items ( ) { return this . _items ; } set items ( items ) { this . _items = items ; this . _onReloadFinished ( ) ; } @ Input ( ) itemCount : number ; @ ContentChildren ( DataTableColumn ) columns : QueryList < DataTableColumn > ; @ ViewChildren ( DataTableRow ) rows : QueryList < DataTableRow > ; @ ContentChild ( 'dataTableExpand' ) expandTemplate : TemplateRef < any > ; @ Input ( ) headerTitle : string ; @ Input ( ) header = true ; @ Input ( ) pagination = true ; @ Input ( ) indexColumn = true ; @ Input ( ) indexColumnHeader = '' ; @ Input ( ) rowColors : RowCallback ; @ Input ( ) rowTooltip : RowCallback ; @ Input ( ) selectColumn = false ; @ Input ( ) multiSelect = true ; @ Input ( ) substituteRows = true ; @ Input ( ) expandableRows = false ; @ Input ( ) translations : DataTableTranslations = defaultTranslations ; @ Input ( ) selectOnRowClick = false ; @ Input ( ) autoReload = true ; @ Input ( ) showReloading = false ; indexColumnVisible : boolean ; selectColumnVisible : boolean ; expandColumnVisible : boolean ; private _sortBy : string ; private _sortAsc = true ; private _offset = 0 ; private _limit = 10 ; @ Input ( ) get sortBy ( ) { return this . _sortBy ; } set sortBy ( value ) { this . _sortBy = value ; this . _triggerReload ( ) ; } @ Input ( ) get sortAsc ( ) { return this . _sortAsc ; } set sortAsc ( value ) { this . _sortAsc = value ; this . _triggerReload ( ) ; } @ Input ( ) get offset ( ) { return this . _offset ; } set offset ( value ) { this . _offset = value ; this . _triggerReload ( ) ; } @ Input ( ) get limit ( ) { return this . _limit ; } set limit ( value ) { this . _limit = value ; this . _triggerReload ( ) ; } @ Input ( ) get page ( ) { return Math . floor ( this . offset / this . limit ) + 1 ; } set page ( value ) { this . offset = ( value - 1 ) * this . limit ; } get lastPage ( ) { return Math . ceil ( this . itemCount / this . limit ) ; } sort ( sortBy , asc ) { this . sortBy = sortBy ; this . sortAsc = asc ; } ngOnInit ( ) { this . _initDefaultValues ( ) ; this . _initDefaultClickEvents ( ) ; this . _updateDisplayParams ( ) ; if ( this . autoReload && this . _scheduledReload == null ) { this . reloadItems ( ) ; } } private _initDefaultValues ( ) { this . indexColumnVisible = this . indexColumn ; this . selectColumnVisible = this . selectColumn ; this . expandColumnVisible = this . expandableRows ; } private _initDefaultClickEvents ( ) { this . headerClick . subscribe ( tableEvent => this . sortColumn ( tableEvent . column ) ) ; if ( this . selectOnRowClick ) { this . rowClick . subscribe ( tableEvent => tableEvent . row . selected = ! tableEvent . row . selected ) ; } } _reloading = false ; get reloading ( ) { return this . _reloading ; } @ Output ( ) reload = new EventEmitter ( ) ; reloadItems ( ) { this . _reloading = true ; this . reload . emit ( this . _getRemoteParameters ( ) ) ; } private _onReloadFinished ( ) { this . _updateDisplayParams ( ) ; this . _selectAllCheckbox = false ; this . _reloading = false ; } _displayParams = < DataTableParams > { } ; get displayParams ( ) { return this . _displayParams ; } _updateDisplayParams ( ) { this . _displayParams = { sortBy : this . sortBy , sortAsc : this . sortAsc , offset : this . offset , limit : this . limit } ; } _scheduledReload = null ; _triggerReload ( ) { if ( this . _scheduledReload ) { clearTimeout ( this . _scheduledReload ) ; } this . _scheduledReload = setTimeout ( ( ) => { this . reloadItems ( ) ; } ) ; } @ Output ( ) rowClick = new EventEmitter ( ) ; @ Output ( ) rowDoubleClick = new EventEmitter ( ) ; @ Output ( ) headerClick = new EventEmitter ( ) ; @ Output ( ) cellClick = new EventEmitter ( ) ; private rowClicked ( row , event ) { this . rowClick . emit ( { row , event } ) ; } private rowDoubleClicked ( row , event ) { this . rowDoubleClick . emit ( { row , event } ) ; } private headerClicked ( column , event ) { if ( ! this . _resizeInProgress ) { this . headerClick . emit ( { column , event } ) ; } else { this . _resizeInProgress = false ; } } private cellClicked ( column , row , event ) { this . cellClick . emit ( { row , column , event } ) ; } private _getRemoteParameters ( ) { let params = < DataTableParams > { } ; if ( this . sortBy ) { params . sortBy = this . sortBy ; params . sortAsc = this . sortAsc ; } if ( this . pagination ) { params . offset = this . offset ; params . limit = this . limit ; } return params ; } private sortColumn ( column ) { if ( column . sortable ) { let ascending = this . sortBy === column . property ? ! this . sortAsc : true ; this . sort ( column . property , ascending ) ; } } get columnCount ( ) { let count = 0 ; count += this . indexColumnVisible ? 1 : 0 ; count += this . selectColumnVisible ? 1 : 0 ; count += this . expandColumnVisible ? 1 : 0 ; this . columns . toArray ( ) . forEach ( column => { count += column . visible ? 1 : 0 ; } ) ; return count ; } private getRowColor ( item , index , row ) { if ( this . rowColors !== undefined ) { return ( < RowCallback > this . rowColors ) ( item , row , index ) ; } } selectedRow : DataTableRow ; selectedRows : DataTableRow [ ] = [ ] ; private _selectAllCheckbox = false ; get selectAllCheckbox ( ) { return this . _selectAllCheckbox ; } set selectAllCheckbox ( value ) { this . _selectAllCheckbox = value ; this . _onSelectAllChanged ( value ) ; } private _onSelectAllChanged ( value ) { this . rows . toArray ( ) . forEach ( row => row . selected = value ) ; } onRowSelectChanged ( row ) { if ( this . multiSelect ) { let index = this . selectedRows . indexOf ( row ) ; if ( row . selected && index < 0 ) { this . selectedRows . push ( row ) ; } else if ( ! row . selected && index >= 0 ) { this . selectedRows . splice ( index , 1 ) ; } } else { if ( row . selected ) { this . selectedRow = row ; } else if ( this . selectedRow === row ) { this . selectedRow = undefined ; } } if ( row . selected && ! this . multiSelect ) { this . rows . toArray ( ) . filter ( row_ => row_ . selected ) . forEach ( row_ => { if ( row_ !== row ) { row_ . selected = false ; } } ) ; } } get substituteItems ( ) { return Array . from ( { length : this . displayParams . limit - this . items . length } ) ; } private _resizeInProgress = false ; private resizeColumnStart ( event , column , columnElement ) { this . _resizeInProgress = true ; drag ( event , { move : ( moveEvent , dx ) => { if ( this . _isResizeInLimit ( columnElement , dx ) ) { column . width = columnElement . offsetWidth + dx ; } } , } ) ; } resizeLimit = 30 ; private _isResizeInLimit ( columnElement , dx ) { if ( ( dx < 0 && ( columnElement . offsetWidth + dx ) <= this . resizeLimit ) || ! columnElement . nextElementSibling || ( dx >= 0 && ( ( < HTMLElement > columnElement . nextElementSibling ) . offsetWidth + dx ) <= this . resizeLimit ) ) { return false ; } return true ; } }