import { ChangeDetectionStrategy , Component , EventEmitter , Input , OnDestroy , OnInit , Output , ViewEncapsulation } from '@angular/core' ; import { Column } from '../../table.types' ; import { FormArray , FormBuilder , FormGroup } from '@angular/forms' ; import { ReplaySubject } from 'rxjs' ; import { debounceTime , distinctUntilChanged , takeUntil } from 'rxjs/operators' ; @ Component ( { selector : 'thead[table-column-search]' , templateUrl : './table-column-search.component.html' , styleUrls : [ './table-column-search.component.scss' ] , changeDetection : ChangeDetectionStrategy . OnPush , encapsulation : ViewEncapsulation . Emulated } ) export class TableColumnSearchComponent < T > implements OnInit , OnDestroy { private private subscriber : ReplaySubject < void > = new ReplaySubject < void > ( ) ; private private readonly debounceTime : number = 500 ; /**
     * Column search form group.
     */ @ Input ( ) form : FormGroup ; /**
     * Is row selected enabled.
     */ @ Input ( ) selectEnabled : boolean = false ; param columns @ Input ( ) columns : Array < Column > ; /**
     * Event emitter when the search input changed.
     */ @ Output ( ) public columnSearchChange : EventEmitter < any [ ] > = new EventEmitter < any [ ] > ( ) ; public constructor ( private fb ) { } param value public static maskRegex ( value ) { try { if ( typeof value === 'boolean' ) { return Boolean ( JSON . parse ( value ) ) ; } } catch ( e ) { } return value . replace ( /[.*+\-?^${}()|[\]\\]/g , '\\$&' ) ; } /**
     * OnInit of `TableColumnSearchComponent`.
     * Auto subscribes to search input control values changes.
     * Emits changes to columnSearchChange EventEmitter.
     */ ngOnInit ( ) { this . initColumnSearchForm ( ) ; this . form . valueChanges . pipe ( debounceTime ( this . debounceTime ) , distinctUntilChanged ( ) , takeUntil ( this . subscriber ) ) . subscribe ( changes => { const validatedResults = [ ] ; for ( const row of changes . rows ) { const validatedRows = [ ] ; for ( const key of Object . keys ( row ) ) { const validatedChange = { name : '' , type : 'text' , data : '' } ; if ( row [ key ] ) { validatedChange . name = key ; validatedChange . type = this . columns . find ( c => c . name === key ) . type ; const value = validatedChange . type === 'checkbox' ? 'unchecked' !== row [ key ] : row [ key ] ; validatedChange . data = TableColumnSearchComponent . maskRegex ( value ) ; if ( 'crossed' !== row [ key ] ) { validatedRows . push ( validatedChange ) ; } } } if ( validatedRows . length > 0 ) { validatedResults . push ( validatedRows ) ; } } this . columnSearchChange . emit ( validatedResults ) ; } ) ; } /**
     * Initialise form
     */ private initColumnSearchForm ( ) { this . form = this . fb . group ( { rows : this . fb . array ( [ this . createItemFormGroup ( ) ] ) } ) ; } private private createItemFormGroup ( ) { const group = { } ; for ( const c of this . columns ) { if ( c . hidden ) { continue ; } group [ c . name ] = '' ; } return this . fb . group ( group ) ; } /**
     * Get FormArray
     */ public get rows ( ) { return this . form . get ( 'rows' ) as FormArray ; } /**
     * Add new form controller
     */ onAddRow ( ) { this . rows . push ( this . createItemFormGroup ( ) ) ; } /**
     * Remove form controller at index
     */ onRemoveRow ( rowIndex ) { this . rows . removeAt ( rowIndex ) ; } public getController ( name , level ) { const group = this . form . controls . rows ; return group . controls [ level ] . controls [ name ] ; } param name param level private public setState ( name , level ) { const control = this . getController ( name , level ) ; switch ( control . value ) { case '' : case 'crossed' : { control . setValue ( 'checked' ) ; break ; } case 'checked' : { control . setValue ( 'unchecked' ) ; break ; } case 'unchecked' : { control . setValue ( 'crossed' ) ; break ; } } } public ngOnDestroy ( ) { this . subscriber . next ( ) ; this . subscriber . complete ( ) ; } }