import { EventHandler , L10n , isNullOrUndefined , extend , closest , getValue } from '@syncfusion/ej2-base' ; import { getActualPropFromColl , isActionPrevent , getColumnByForeignKeyValue } from '../base/util' ; import { remove , matches } from '@syncfusion/ej2-base' ; import { DataUtil , Predicate , Query , DataManager } from '@syncfusion/ej2-data' ; import { FilterSettings , Grid } from '../base/grid' ; import { IGrid , IAction , NotifyArgs , IFilterOperator , IValueFormatter } from '../base/interface' ; import * as events from '../base/constant' ; import { CellType } from '../base/enum' ; import { PredicateModel } from '../base/grid-model' ; import { RowRenderer } from '../renderer/row-renderer' ; import { ServiceLocator } from '../services/service-locator' ; import { CellRendererFactory } from '../services/cell-render-factory' ; import { Column } from '../models/column' ; import { Cell } from '../models/cell' ; import { Row } from '../models/row' ; import { FilterCellRenderer } from '../renderer/filter-cell-renderer' ; import { parentsUntil } from '../base/util' ; import { FilterMenuRenderer } from '../renderer/filter-menu-renderer' ; import { CheckBoxFilter } from '../actions/checkbox-filter' ; import { ExcelFilter } from '../actions/excel-filter' ; /**
 *
 * The `Filter` module is used to handle filtering action.
 */ export class Filter implements IAction { private filterSettings : FilterSettings ; private element : Element ; private value : string | number | Date | boolean ; private predicate : string = 'and' ; private operator : string ; private column : Column ; private fieldName : string ; private matchCase : boolean ; private ignoreAccent : boolean ; private timer : number ; private filterStatusMsg : string ; private currentFilterObject : PredicateModel ; private isRemove : boolean ; private contentRefresh : boolean = true ; private values : Object = { } ; private cellText : Object = { } ; private nextFlMenuOpen : string = '' ; private type : Object = { 'Menu' : FilterMenuRenderer , 'CheckBox' : CheckBoxFilter , 'Excel' : ExcelFilter } ; private filterModule : { openDialog : Function ; closeDialog : Function ; destroy : Function ; } ; private filterOperators : IFilterOperator = { contains : 'contains' , endsWith : 'endswith' , equal : 'equal' , greaterThan : 'greaterthan' , greaterThanOrEqual : 'greaterthanorequal' , lessThan : 'lessthan' , lessThanOrEqual : 'lessthanorequal' , notEqual : 'notequal' , startsWith : 'startswith' } ; private fltrDlgDetails : { field ? : string ; isOpen ? : boolean ; } = { field : '' , isOpen : false } ; private customOperators : Object ; private parent : IGrid ; private serviceLocator : ServiceLocator ; private l10n : L10n ; private valueFormatter : IValueFormatter ; private actualPredicate : { [ key ] : PredicateModel [ ] ; } = { } ; hidden constructor ( parent ? , filterSettings ? , serviceLocator ? ) { this . parent = parent ; this . filterSettings = filterSettings ; this . serviceLocator = serviceLocator ; this . addEventListener ( ) ; } return { void } hidden public render ( e ? ) { if ( DataUtil . getObject ( 'args.isFrozen' , e ) ) { return ; } let gObj = this . parent ; this . l10n = this . serviceLocator . getService < L10n > ( 'localization' ) ; this . getLocalizedCustomOperators ( ) ; if ( this . parent . filterSettings . type === 'FilterBar' ) { if ( gObj . columns . length ) { let fltrElem = this . parent . element . querySelector ( '.e-filterbar' ) ; if ( fltrElem ) { remove ( fltrElem ) ; } let rowRenderer = new RowRenderer < Column > ( this . serviceLocator , CellType . Filter , gObj ) ; let row ; let cellrender = this . serviceLocator . getService < CellRendererFactory > ( 'cellRendererFactory' ) ; cellrender . addCellRenderer ( CellType . Filter , new FilterCellRenderer ( this . parent , this . serviceLocator ) ) ; this . valueFormatter = this . serviceLocator . getService < IValueFormatter > ( 'valueFormatter' ) ; rowRenderer . element = this . parent . createElement ( 'tr' , { className : 'e-filterbar' } ) ; row = this . generateRow ( ) ; row . data = this . values ; this . parent . getHeaderContent ( ) . querySelector ( 'thead' ) . appendChild ( rowRenderer . element ) ; this . element = rowRenderer . render ( row , < Column [ ] > gObj . getColumns ( ) , null , null , rowRenderer . element ) ; let detail = this . element . querySelector ( '.e-detailheadercell' ) ; if ( detail ) { detail . className = 'e-filterbarcell e-mastercell' ; } let gCells = [ ] . slice . call ( this . element . querySelectorAll ( '.e-grouptopleftcell' ) ) ; if ( gCells . length ) { gCells [ gCells . length - 1 ] . classList . add ( 'e-lastgrouptopleftcell' ) ; } this . wireEvents ( ) ; this . parent . notify ( events . freezeRender , { case : 'filter' } ) ; } } } return { void } hidden public destroy ( ) { let gridElement = this . parent . element ; if ( ! gridElement || ( ! gridElement . querySelector ( '.e-gridheader' ) && ! gridElement . querySelector ( '.e-gridcontent' ) ) ) { return ; } if ( this . filterModule ) { this . filterModule . destroy ( ) ; } this . filterSettings . columns = [ ] ; this . updateFilterMsg ( ) ; this . removeEventListener ( ) ; this . unWireEvents ( ) ; if ( this . element ) { remove ( this . element ) ; let filterBarElement = this . parent . getHeaderContent ( ) . querySelector ( '.e-filterbar' ) ; if ( this . parent . getFrozenColumns ( ) && filterBarElement ) { remove ( filterBarElement ) ; } } } private generateRow ( index ? ) { let options = { } ; let row = new Row < Column > ( options ) ; row . cells = this . generateCells ( ) ; return row ; } private generateCells ( ) { let cells = [ ] ; if ( this . parent . allowGrouping ) { for ( let c = 0 , len = this . parent . groupSettings . columns . length ; c < len ; c ++ ) { cells . push ( this . generateCell ( { } as Column , CellType . HeaderIndent ) ) ; } } if ( this . parent . detailTemplate || this . parent . childGrid ) { cells . push ( this . generateCell ( { } as Column , CellType . DetailHeader ) ) ; } for ( let dummy of this . parent . getColumns ( ) as Column [ ] ) { cells . push ( this . generateCell ( dummy ) ) ; } return cells ; } private generateCell ( column , cellType ? ) { let opt = { 'visible' : column . visible , 'isDataCell' : false , 'rowId' : '' , 'column' : column , 'cellType' : cellType ? cellType : CellType . Filter , 'attributes' : { title : this . l10n . getConstant ( 'FilterbarTitle' ) } } ; return new Cell < Column > ( opt ) ; } return { void } hidden public updateModel ( ) { let col = this . parent . getColumnByField ( this . fieldName ) ; let field = col . isForeignColumn ( ) ? col . foreignKeyValue : this . fieldName ; this . currentFilterObject = { field : field , operator : this . operator , value : this . value as string , predicate : this . predicate , matchCase : this . matchCase , ignoreAccent : this . ignoreAccent , actualFilterValue : { } , actualOperator : { } } ; let index = this . getFilteredColsIndexByField ( col ) ; if ( index > - 1 ) { this . filterSettings . columns [ index ] = this . currentFilterObject ; } else { this . filterSettings . columns . push ( this . currentFilterObject ) ; } this . filterSettings . columns = this . filterSettings . columns ; this . parent . dataBind ( ) ; } private getFilteredColsIndexByField ( col ) { let cols = this . filterSettings . columns ; for ( let i = 0 , len = cols . length ; i < len ; i ++ ) { if ( cols [ i ] . field === col . field || ( col . isForeignColumn ( ) && cols [ i ] . field === col . foreignKeyValue ) ) { return i ; } } return - 1 ; } return { void } hidden public onActionComplete ( e ) { let args = ! this . isRemove ? { currentFilterObject : this . currentFilterObject , currentFilteringColumn : ! isNullOrUndefined ( this . column ) ? this . column . field : undefined , columns : this . filterSettings . columns , requestType : 'filtering' , type : events . actionComplete } : { requestType : 'filtering' , type : events . actionComplete } ; this . parent . trigger ( events . actionComplete , extend ( e , args ) ) ; this . isRemove = false ; } private wireEvents ( ) { EventHandler . add ( this . parent . getHeaderContent ( ) , 'keyup' , this . keyUpHandler , this ) ; } private unWireEvents ( ) { EventHandler . remove ( this . parent . getHeaderContent ( ) , 'keyup' , this . keyUpHandler ) ; } private enableAfterRender ( e ) { if ( e . module === this . getModuleName ( ) && e . enable ) { this . render ( ) ; } } private initialEnd ( ) { this . parent . off ( events . contentReady , this . initialEnd ) ; if ( this . parent . getColumns ( ) . length && this . filterSettings . columns . length ) { let gObj = this . parent ; this . contentRefresh = false ; for ( let col of gObj . filterSettings . columns ) { this . filterByColumn ( col . field , col . operator , col . value as string , col . predicate , col . matchCase , col . ignoreAccent , col . actualFilterValue , col . actualOperator ) ; } this . updateFilterMsg ( ) ; this . contentRefresh = true ; } } hidden public addEventListener ( ) { if ( this . parent . isDestroyed ) { return ; } this . parent . on ( events . uiUpdate , this . enableAfterRender , this ) ; this . parent . on ( events . filterComplete , this . onActionComplete , this ) ; this . parent . on ( events . inBoundModelChanged , this . onPropertyChanged , this ) ; this . parent . on ( events . keyPressed , this . keyUpHandler , this ) ; this . parent . on ( events . columnPositionChanged , this . columnPositionChanged , this ) ; this . parent . on ( events . headerRefreshed , this . render , this ) ; this . parent . on ( events . contentReady , this . initialEnd , this ) ; this . parent . on ( events . filterMenuClose , this . filterMenuClose , this ) ; EventHandler . add ( document , 'click' , this . clickHandler , this ) ; this . parent . on ( events . filterOpen , this . columnMenuFilter , this ) ; this . parent . on ( events . click , this . filterIconClickHandler , this ) ; } hidden public removeEventListener ( ) { EventHandler . remove ( document , 'click' , this . clickHandler ) ; if ( this . parent . isDestroyed ) { return ; } this . parent . off ( events . uiUpdate , this . enableAfterRender ) ; this . parent . off ( events . filterComplete , this . onActionComplete ) ; this . parent . off ( events . inBoundModelChanged , this . onPropertyChanged ) ; this . parent . off ( events . keyPressed , this . keyUpHandler ) ; this . parent . off ( events . columnPositionChanged , this . columnPositionChanged ) ; this . parent . off ( events . headerRefreshed , this . render ) ; this . parent . off ( events . filterOpen , this . columnMenuFilter ) ; this . parent . off ( events . filterMenuClose , this . filterMenuClose ) ; this . parent . off ( events . click , this . filterIconClickHandler ) ; } private filterMenuClose ( args ) { this . fltrDlgDetails . isOpen = false ; } param { string } fieldName param { string } filterOperator param { string | number | Date | boolean } filterValue param { string } predicate param { boolean } matchCase param { boolean } ignoreAccent param { string } actualFilterValue param { string } actualOperator return { void } public filterByColumn ( fieldName , filterOperator , filterValue , predicate ? , matchCase ? , ignoreAccent ? , actualFilterValue ? , actualOperator ? ) { let gObj = this . parent ; let filterCell ; this . column = gObj . getColumnByField ( fieldName ) ; if ( this . filterSettings . type === 'FilterBar' ) { filterCell = gObj . getHeaderContent ( ) . querySelector ( '[id=\'' + this . column . field + '_filterBarcell\']' ) as HTMLInputElement ; } if ( ! isNullOrUndefined ( this . column . allowFiltering ) && ! this . column . allowFiltering ) { return ; } if ( isActionPrevent ( gObj ) ) { gObj . notify ( events . preventBatch , { instance : this , handler : this . filterByColumn , arg1 : fieldName , arg2 : filterOperator , arg3 : filterValue , arg4 : predicate , arg5 : matchCase , arg6 : ignoreAccent , arg7 : actualFilterValue , arg8 : actualOperator } ) ; return ; } this . value = filterValue ; this . matchCase = matchCase || false ; this . ignoreAccent = this . ignoreAccent = ! isNullOrUndefined ( ignoreAccent ) ? ignoreAccent : this . parent . filterSettings . ignoreAccent ; this . fieldName = fieldName ; this . predicate = predicate || 'and' ; this . operator = filterOperator ; filterValue = ! isNullOrUndefined ( filterValue ) && filterValue . toString ( ) ; if ( this . column . type === 'number' || this . column . type === 'date' ) { this . matchCase = true ; } gObj . getColumnHeaderByField ( fieldName ) . setAttribute ( 'aria-filtered' , 'true' ) ; if ( filterValue . length < 1 || this . checkForSkipInput ( this . column , filterValue ) ) { this . filterStatusMsg = filterValue . length < 1 ? '' : this . l10n . getConstant ( 'InvalidFilterMessage' ) ; this . updateFilterMsg ( ) ; return ; } if ( filterCell && this . filterSettings . type === 'FilterBar' && filterCell . value !== filterValue ) { filterCell . value = filterValue ; } if ( ! isNullOrUndefined ( this . column . format ) ) { this . applyColumnFormat ( filterValue ) ; } else { this . values [ this . column . field ] = filterValue ; } this . actualPredicate [ this . fieldName ] = [ { field : this . fieldName , predicate : predicate , matchCase : matchCase , ignoreAccent : ignoreAccent , operator : this . operator , value : this . value , type : this . column . type } ] ; this . addFilteredClass ( this . fieldName ) ; if ( this . checkAlreadyColFiltered ( this . column . field ) ) { return ; } this . updateModel ( ) ; } private applyColumnFormat ( filterValue ) { let getFlvalue = ( this . column . type === 'date' || this . column . type === 'datetime' ) ? new Date ( filterValue as string ) : parseFloat ( filterValue as string ) ; this . values [ this . column . field ] = this . setFormatForFlColumn ( getFlvalue , this . column ) ; } private onPropertyChanged ( e ) { if ( e . module !== this . getModuleName ( ) ) { return ; } for ( let prop of Object . keys ( e . properties ) ) { switch ( prop ) { case 'columns' : if ( this . contentRefresh ) { this . parent . notify ( events . modelChanged , { currentFilterObject : this . currentFilterObject , currentFilteringColumn : this . column ? this . column . field : undefined , columns : this . filterSettings . columns , requestType : 'filtering' , type : events . actionBegin } ) ; this . refreshFilterSettings ( ) ; this . updateFilterMsg ( ) ; this . updateFilter ( ) ; } break ; case 'showFilterBarStatus' : if ( e . properties [ prop ] ) { this . updateFilterMsg ( ) ; } else if ( this . parent . allowPaging ) { this . parent . updateExternalMessage ( '' ) ; } break ; case 'type' : this . parent . refreshHeader ( ) ; this . refreshFilterSettings ( ) ; break ; } } } private refreshFilterSettings ( ) { if ( this . filterSettings . type === 'FilterBar' ) { for ( let i = 0 ; i < this . filterSettings . columns . length ; i ++ ) { this . column = this . parent . getColumnByField ( this . filterSettings . columns [ i ] . field ) || getColumnByForeignKeyValue ( this . filterSettings . columns [ i ] . field , this . parent . getForeignKeyColumns ( ) ) ; let filterValue = this . filterSettings . columns [ i ] . value ; filterValue = ! isNullOrUndefined ( filterValue ) && filterValue . toString ( ) ; if ( ! isNullOrUndefined ( this . column . format ) ) { this . applyColumnFormat ( filterValue ) ; } else { let key = this . filterSettings . columns [ i ] . field ; this . values [ key ] = this . filterSettings . columns [ i ] . value ; } let filterElement = this . getFilterBarElement ( this . filterSettings . columns [ i ] . field ) ; if ( filterElement ) { if ( ! isNullOrUndefined ( this . cellText [ this . filterSettings . columns [ i ] . field ] ) ) { filterElement . value = this . cellText [ this . filterSettings . columns [ i ] . field ] ; } else { filterElement . value = this . filterSettings . columns [ i ] . value as string ; } } } if ( this . filterSettings . columns . length === 0 ) { let col = this . parent . getColumns ( ) ; for ( let i = 0 ; i < col . length ; i ++ ) { let filterElement = this . getFilterBarElement ( col [ i ] . field ) ; if ( filterElement && filterElement . value !== '' ) { filterElement . value = '' ; delete this . values [ col [ i ] . field ] ; } } } } } private getFilterBarElement ( col ) { let selector = '[id=\'' + col + '_filterBarcell\']' ; let filterElement ; if ( selector && ! isNullOrUndefined ( this . element ) ) { filterElement = ( this . element . querySelector ( selector ) as HTMLInputElement ) ; } return filterElement ; } private public refreshFilter ( ) { this . refreshFilterSettings ( ) ; this . updateFilterMsg ( ) ; } return { void } public clearFiltering ( ) { let cols = getActualPropFromColl ( this . filterSettings . columns ) ; if ( isActionPrevent ( this . parent ) ) { this . parent . notify ( events . preventBatch , { instance : this , handler : this . clearFiltering } ) ; return ; } for ( let i = 0 , len = cols . length ; i < len ; i ++ ) { this . removeFilteredColsByField ( cols [ i ] . field , false ) ; } if ( this . parent . filterSettings . columns . length === 0 && this . parent . element . querySelector ( '.e-filtered' ) ) { let fltrElement = [ ] . slice . call ( this . parent . element . querySelectorAll ( '.e-filtered' ) ) ; for ( let i = 0 , len = fltrElement . length ; i < len ; i ++ ) { fltrElement [ 0 ] . removeAttribute ( 'aria-filtered' ) ; fltrElement [ 0 ] . classList . remove ( 'e-filtered' ) ; } } this . isRemove = true ; this . filterStatusMsg = '' ; this . updateFilterMsg ( ) ; } private checkAlreadyColFiltered ( field ) { let columns = this . filterSettings . columns ; for ( let col of columns ) { if ( col . field === field && col . value === this . value && col . operator === this . operator && col . predicate === this . predicate ) { return true ; } } return false ; } private columnMenuFilter ( args ) { this . column = args . col ; let ele = closest ( args . target , '#' + args . id ) ; if ( args . isClose && ! ele ) { this . filterModule . closeDialog ( ) ; } else if ( ele ) { this . filterDialogOpen ( this . column , args . target ) ; } } private filterDialogOpen ( col , target , left ? , top ? ) { let gObj = this . parent ; if ( this . filterModule ) { this . filterModule . closeDialog ( ) ; } this . filterModule = new this . type [ col . filter . type || this . parent . filterSettings . type ] ( this . parent , gObj . filterSettings , this . serviceLocator , this . customOperators , this ) ; let dataSource = col . filter . dataSource || gObj . getDataModule ( ) . dataManager ; this . filterModule . openDialog ( { type : col . type , field : col . field , displayName : col . headerText , dataSource : dataSource , format : col . format , filteredColumns : gObj . filterSettings . columns , target : target , sortedColumns : gObj . sortSettings . columns , formatFn : col . getFormatter ( ) , parserFn : col . getParser ( ) , query : gObj . query , template : col . getFilterItemTemplate ( ) , hideSearchbox : isNullOrUndefined ( col . filter . hideSearchbox ) ? false : col . filter . hideSearchbox , handler : this . filterHandler . bind ( this ) , localizedStrings : gObj . getLocaleConstants ( ) , position : { X : left , Y : top } , column : col , foreignKeyValue : col . foreignKeyValue , actualPredicate : this . actualPredicate , localeObj : this . parent . localeObj } ) ; } param { string } field param { boolean } isClearFilterBar return { void } hidden public removeFilteredColsByField ( field , isClearFilterBar ? ) { let fCell ; let cols = this . filterSettings . columns ; if ( isActionPrevent ( this . parent ) ) { let args = { instance : this , handler : this . removeFilteredColsByField , arg1 : field , arg2 : isClearFilterBar } ; this . parent . notify ( events . preventBatch , args ) ; return ; } for ( let i = 0 , len = cols . length ; i < len ; i ++ ) { let column = this . parent . getColumnByField ( field ) || getColumnByForeignKeyValue ( field , this . parent . getForeignKeyColumns ( ) ) ; if ( cols [ i ] . field === field || cols [ i ] . field === column . foreignKeyValue ) { if ( this . filterSettings . type === 'FilterBar' && ! isClearFilterBar ) { let selector = '[id=\'' + cols [ i ] . field + '_filterBarcell\']' ; fCell = this . parent . getHeaderContent ( ) . querySelector ( selector ) as HTMLInputElement ; fCell . value = '' ; delete this . values [ field ] ; } cols . splice ( i , 1 ) ; let fltrElement = this . parent . getColumnHeaderByField ( column . field ) ; fltrElement . removeAttribute ( 'aria-filtered' ) ; if ( this . filterSettings . type !== 'FilterBar' ) { let iconClass = this . parent . showColumnMenu ? '.e-columnmenu' : '.e-icon-filter' ; fltrElement . querySelector ( iconClass ) . classList . remove ( 'e-filtered' ) ; } this . isRemove = true ; if ( this . actualPredicate [ field ] ) { delete this . actualPredicate [ field ] ; } if ( this . values [ field ] ) { delete this . values [ field ] ; } this . parent . notify ( events . modelChanged , { requestType : 'filtering' , type : events . actionBegin , currentFilterObject : { field : column . field , operator : this . operator , value : this . value as string , predicate : this . predicate , matchCase : this . matchCase , ignoreAccent : this . ignoreAccent , actualFilterValue : { } , actualOperator : { } } , currentFilterColumn : column } ) ; break ; } } this . updateFilterMsg ( ) ; } private protected getModuleName ( ) { return 'filter' ; } private keyUpHandler ( e ) { let gObj = this . parent ; let target = e . target as HTMLInputElement ; if ( target && matches ( target , '.e-filterbar input' ) ) { let closeHeaderEle = closest ( target , 'th.e-filterbarcell' ) ; this . column = gObj . getColumnByUid ( closeHeaderEle . getAttribute ( 'e-mappinguid' ) ) ; if ( ! this . column ) { return ; } if ( ( this . filterSettings . mode === 'Immediate' || e . keyCode === 13 ) && e . keyCode !== 9 ) { this . value = target . value . trim ( ) ; this . processFilter ( e ) ; } } } private updateCrossIcon ( element ) { if ( element . value . length ) { element . nextElementSibling . classList . remove ( 'e-hide' ) ; } } private updateFilterMsg ( ) { if ( this . filterSettings . type === 'FilterBar' ) { let gObj = this . parent ; let getFormatFlValue ; let columns = this . filterSettings . columns ; let formater = this . serviceLocator . getService < IValueFormatter > ( 'valueFormatter' ) ; let column ; let value ; if ( ! this . filterSettings . showFilterBarStatus ) { return ; } if ( columns . length > 0 && this . filterStatusMsg !== this . l10n . getConstant ( 'InvalidFilterMessage' ) ) { this . filterStatusMsg = '' ; for ( let index = 0 ; index < columns . length ; index ++ ) { column = gObj . getColumnByField ( columns [ index ] . field ) || getColumnByForeignKeyValue ( columns [ index ] . field , this . parent . getForeignKeyColumns ( ) ) ; if ( index ) { this . filterStatusMsg += ' && ' ; } if ( ! isNullOrUndefined ( column . format ) ) { let flValue = ( column . type === 'date' || column . type === 'datetime' ) ? new Date ( this . values [ column . field ] ) : this . values [ column . field ] ; if ( ! ( column . type === 'date' || column . type === 'datetime' ) ) { let formater = this . serviceLocator . getService < IValueFormatter > ( 'valueFormatter' ) ; getFormatFlValue = formater . toView ( flValue , column . getParser ( ) ) . toString ( ) ; } else { getFormatFlValue = this . setFormatForFlColumn ( flValue , column ) ; } this . filterStatusMsg += column . headerText + ': ' + getFormatFlValue ; } else { this . filterStatusMsg += column . headerText + ': ' + this . values [ column . field ] ; } } } if ( gObj . allowPaging ) { gObj . updateExternalMessage ( this . filterStatusMsg ) ; } this . filterStatusMsg = '' ; } } private setFormatForFlColumn ( value , column ) { let formater = this . serviceLocator . getService < IValueFormatter > ( 'valueFormatter' ) ; return formater . toView ( value , column . getFormatter ( ) ) . toString ( ) ; } private checkForSkipInput ( column , value ) { let isSkip ; let skipInput ; if ( column . type === 'number' ) { skipInput = [ '=' , ' ' , '!' ] ; if ( DataUtil . operatorSymbols [ value ] || skipInput . indexOf ( value ) > - 1 ) { isSkip = true ; } } else if ( column . type === 'string' ) { skipInput = [ '>' , '<' , '=' , '!' ] ; for ( let val of value ) { if ( skipInput . indexOf ( val ) > - 1 ) { isSkip = true ; } } } return isSkip ; } private processFilter ( e ) { this . stopTimer ( ) ; this . startTimer ( e ) ; } private startTimer ( e ) { this . timer = window . setInterval ( ( ) => { this . onTimerTick ( ) ; } , e . keyCode === 13 ? 0 : this . filterSettings . immediateModeDelay ) ; } private stopTimer ( ) { window . clearInterval ( this . timer ) ; } private onTimerTick ( ) { let selector = '[id=\'' + this . column . field + '_filterBarcell\']' ; let filterElement = ( this . element . querySelector ( selector ) as HTMLInputElement ) ; if ( ! filterElement && this . parent . getFrozenColumns ( ) ) { filterElement = ( this . parent . getHeaderContent ( ) . querySelector ( selector ) as HTMLInputElement ) ; } let filterValue ; this . cellText [ this . column . field ] = filterElement . value ; this . stopTimer ( ) ; if ( ! isNullOrUndefined ( this . column . filterBarTemplate ) ) { let templateRead = this . column . filterBarTemplate . read as Function ; if ( typeof templateRead === 'string' ) { templateRead = getValue ( templateRead , window ) ; } if ( ! isNullOrUndefined ( templateRead ) ) { this . value = templateRead . call ( this , filterElement ) ; } } else { filterValue = JSON . parse ( JSON . stringify ( filterElement . value ) ) ; } if ( isNullOrUndefined ( this . value ) || this . value === '' ) { this . removeFilteredColsByField ( this . column . field ) ; return ; } this . validateFilterValue ( this . value as string ) ; this . filterByColumn ( this . column . field , this . operator , this . value as string , this . predicate , this . matchCase , this . ignoreAccent ) ; filterElement . value = filterValue ; this . updateFilterMsg ( ) ; } private validateFilterValue ( value ) { let gObj = this . parent ; let skipInput ; let index ; this . matchCase = true ; switch ( this . column . type ) { case 'number' : this . operator = this . filterOperators . equal ; skipInput = [ '>' , '<' , '=' , '!' ] ; for ( let i = 0 ; i < value . length ; i ++ ) { if ( skipInput . indexOf ( value [ i ] ) > - 1 ) { index = i ; break ; } } this . getOperator ( value . substring ( index ) ) ; if ( index !== 0 ) { this . value = value . substring ( 0 , index ) ; } if ( this . value !== '' && value . length >= 1 ) { this . value = this . valueFormatter . fromView ( this . value as string , this . column . getParser ( ) , this . column . type ) ; } if ( isNaN ( this . value as number ) ) { this . filterStatusMsg = this . l10n . getConstant ( 'InvalidFilterMessage' ) ; } break ; case 'date' : case 'datetime' : this . operator = this . filterOperators . equal ; if ( this . value !== '' && ! ( this . value instanceof Date ) ) { this . getOperator ( value ) ; this . value = this . valueFormatter . fromView ( this . value as string , this . column . getParser ( ) , this . column . type ) ; if ( isNullOrUndefined ( this . value ) ) { this . filterStatusMsg = this . l10n . getConstant ( 'InvalidFilterMessage' ) ; } } break ; case 'string' : this . matchCase = false ; if ( value . charAt ( 0 ) === '*' ) { this . value = ( this . value as string ) . slice ( 1 ) ; this . operator = this . filterOperators . startsWith ; } else if ( value . charAt ( value . length - 1 ) === '%' ) { this . value = ( this . value as string ) . slice ( 0 , - 1 ) ; this . operator = this . filterOperators . startsWith ; } else if ( value . charAt ( 0 ) === '%' ) { this . value = ( this . value as string ) . slice ( 1 ) ; this . operator = this . filterOperators . endsWith ; } else { this . operator = this . filterOperators . startsWith ; } break ; case 'boolean' : if ( value . toLowerCase ( ) === 'true' || value === '1' ) { this . value = true ; } else if ( value . toLowerCase ( ) === 'false' || value === '0' ) { this . value = false ; } else if ( value . length ) { this . filterStatusMsg = this . l10n . getConstant ( 'InvalidFilterMessage' ) ; } this . operator = this . filterOperators . equal ; break ; default : this . operator = this . filterOperators . equal ; } } private getOperator ( value ) { let singleOp = value . charAt ( 0 ) ; let multipleOp = value . slice ( 0 , 2 ) ; let operators = extend ( { '=' : this . filterOperators . equal , '!' : this . filterOperators . notEqual } , DataUtil . operatorSymbols ) ; if ( operators . hasOwnProperty ( singleOp ) || operators . hasOwnProperty ( multipleOp ) ) { this . operator = operators [ singleOp ] ; this . value = value . substring ( 1 ) ; if ( ! this . operator ) { this . operator = operators [ multipleOp ] ; this . value = value . substring ( 2 ) ; } } if ( this . operator === this . filterOperators . lessThan || this . operator === this . filterOperators . greaterThan ) { if ( ( this . value as string ) . charAt ( 0 ) === '=' ) { this . operator = this . operator + 'orequal' ; this . value = ( this . value as string ) . substring ( 1 ) ; } } } private columnPositionChanged ( e ) { if ( this . parent . filterSettings . type !== 'FilterBar' ) { return ; } } private getLocalizedCustomOperators ( ) { let numOptr = [ { value : 'equal' , text : this . l10n . getConstant ( 'Equal' ) } , { value : 'greaterthan' , text : this . l10n . getConstant ( 'GreaterThan' ) } , { value : 'greaterthanorequal' , text : this . l10n . getConstant ( 'GreaterThanOrEqual' ) } , { value : 'lessthan' , text : this . l10n . getConstant ( 'LessThan' ) } , { value : 'lessthanorequal' , text : this . l10n . getConstant ( 'LessThanOrEqual' ) } , { value : 'notequal' , text : this . l10n . getConstant ( 'NotEqual' ) } ] ; this . customOperators = { stringOperator : [ { value : 'startswith' , text : this . l10n . getConstant ( 'StartsWith' ) } , { value : 'endswith' , text : this . l10n . getConstant ( 'EndsWith' ) } , { value : 'contains' , text : this . l10n . getConstant ( 'Contains' ) } , { value : 'equal' , text : this . l10n . getConstant ( 'Equal' ) } , { value : 'notequal' , text : this . l10n . getConstant ( 'NotEqual' ) } ] , numberOperator : numOptr , dateOperator : numOptr , datetimeOperator : numOptr , booleanOperator : [ { value : 'equal' , text : this . l10n . getConstant ( 'Equal' ) } , { value : 'notequal' , text : this . l10n . getConstant ( 'NotEqual' ) } ] } ; } ; private filterIconClickHandler ( e ) { let target = e . target as Element ; if ( target . classList . contains ( 'e-filtermenudiv' ) && ( this . parent . filterSettings . type === 'Menu' || this . parent . filterSettings . type === 'CheckBox' || this . parent . filterSettings . type === 'Excel' ) ) { let gObj = this . parent ; let col = gObj . getColumnByUid ( parentsUntil ( target , 'e-headercell' ) . firstElementChild . getAttribute ( 'e-mappinguid' ) ) ; let gClient = gObj . element . getBoundingClientRect ( ) ; let fClient = target . getBoundingClientRect ( ) ; this . column = col ; if ( this . fltrDlgDetails . field === col . field && this . fltrDlgDetails . isOpen ) { return ; } if ( this . filterModule ) { this . filterModule . closeDialog ( ) ; } this . fltrDlgDetails = { field : col . field , isOpen : true } ; this . filterDialogOpen ( this . column , target , fClient . right - gClient . left , fClient . bottom - gClient . top ) ; } } private clickHandler ( e ) { if ( this . filterSettings . mode === 'Immediate' || this . parent . filterSettings . type === 'Menu' || this . parent . filterSettings . type === 'CheckBox' || this . parent . filterSettings . type === 'Excel' ) { let gObj = this . parent ; let target = e . target as Element ; let datepickerEle = target . classList . contains ( 'e-day' ) ; if ( parentsUntil ( target , 'e-filter-popup' ) || target . classList . contains ( 'e-filtermenudiv' ) ) { return ; } else if ( this . filterModule && ( ! parentsUntil ( target , 'e-popup-wrapper' ) && ( ! closest ( target , '.e-filter-item.e-menu-item' ) ) && ( ! parentsUntil ( target , 'e-popup' ) ) ) && ! datepickerEle ) { this . filterModule . closeDialog ( target ) ; } if ( this . filterSettings . mode === 'Immediate' && target . classList . contains ( 'e-clear-icon' ) ) { let targetText = target . previousElementSibling as HTMLInputElement ; this . removeFilteredColsByField ( targetText . id . slice ( 0 , - 14 ) ) ; } } } private filterHandler ( args ) { let filterIconElement ; this . actualPredicate [ args . field ] = args . actualPredicate ; let dataManager = new DataManager ( this . filterSettings . columns as JSON [ ] ) ; let query = new Query ( ) . where ( 'field' , this . filterOperators . equal , args . field ) ; let result = dataManager . executeLocal ( query ) as { field : string ; } [ ] ; for ( let i = 0 ; i < result . length ; i ++ ) { let index = - 1 ; for ( let j = 0 ; j < this . filterSettings . columns . length ; j ++ ) { if ( result [ i ] . field === this . filterSettings . columns [ j ] . field ) { index = j ; break ; } } if ( index !== - 1 ) { this . filterSettings . columns . splice ( index , 1 ) ; } } if ( this . values [ args . field ] ) { delete this . values [ args . field ] ; } let iconClass = this . parent . showColumnMenu ? '.e-columnmenu' : '.e-icon-filter' ; filterIconElement = this . parent . getColumnHeaderByField ( args . field ) . querySelector ( iconClass ) ; if ( args . action === 'filtering' ) { this . filterSettings . columns = this . filterSettings . columns . concat ( args . filterCollection ) ; if ( this . filterSettings . columns . length && filterIconElement ) { filterIconElement . classList . add ( 'e-filtered' ) ; } } else { if ( filterIconElement ) { filterIconElement . classList . remove ( 'e-filtered' ) ; } this . parent . renderModule . refresh ( ) ; } this . parent . dataBind ( ) ; } private updateFilter ( ) { let cols = this . filterSettings . columns ; for ( let i = 0 ; i < cols . length ; i ++ ) { this . column = this . parent . getColumnByField ( cols [ i ] . field ) || getColumnByForeignKeyValue ( cols [ i ] . field , this . parent . getForeignKeyColumns ( ) ) ; let fieldName = cols [ i ] . field ; if ( ! this . parent . getColumnByField ( cols [ i ] . field ) ) { fieldName = getColumnByForeignKeyValue ( cols [ i ] . field , this . parent . getForeignKeyColumns ( ) ) . field ; } this . refreshFilterIcon ( fieldName , cols [ i ] . operator , cols [ i ] . value , cols [ i ] . type , cols [ i ] . predicate , cols [ i ] . matchCase , cols [ i ] . ignoreAccent ) ; } } private refreshFilterIcon ( fieldName , operator , value , type ? , predicate ? , matchCase ? , ignoreAccent ? ) { this . actualPredicate [ fieldName ] = [ { field : fieldName , predicate : predicate , matchCase : matchCase , ignoreAccent : ignoreAccent , operator : operator , value : value , type : type } ] ; this . addFilteredClass ( fieldName ) ; } private addFilteredClass ( fieldName ) { let filterIconElement ; filterIconElement = this . parent . getColumnHeaderByField ( fieldName ) . querySelector ( '.e-icon-filter' ) ; if ( filterIconElement ) { filterIconElement . classList . add ( 'e-filtered' ) ; } } }