import { Directive , ElementRef , forwardRef , HostListener , Provider , Renderer2 } from '@angular/core' ; import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ; import { MultiSelectOptionDirective } from './multi-select-option.directive' ; ignore const NGQP_MULTI_SELECT_VALUE_ACCESSOR = { provide : NG_VALUE_ACCESSOR , useExisting : forwardRef ( ( ) => MultiSelectControlValueAccessorDirective ) , multi : true } ; ignore @ Directive ( { selector : 'select[multiple][queryParamName],select[multiple][queryParam]' , providers : [ NGQP_MULTI_SELECT_VALUE_ACCESSOR ] , } ) export class MultiSelectControlValueAccessorDirective < T > implements ControlValueAccessor { private selectedIds : string [ ] = [ ] ; private options = new Map < string , MultiSelectOptionDirective < T > > ( ) ; private optionMap = new Map < string , T > ( ) ; private idCounter = 0 ; private fnChange = ( _ ) => { } ; private fnTouched = ( ) => { } ; @ HostListener ( 'change' ) public onChange ( ) { this . selectedIds = Array . from ( this . options . entries ( ) ) . filter ( ( [ id , option ] ) => option . selected ) . map ( ( [ id ] ) => id ) ; const values = this . selectedIds . map ( id => this . optionMap . get ( id ) ! ) ; this . fnChange ( values ) ; } @ HostListener ( 'blur' ) public onTouched ( ) { this . fnTouched ( ) ; } constructor ( private renderer , private elementRef ) { } public writeValue ( values ) { values = values === null ? < T [ ] > [ ] : values ; if ( ! Array . isArray ( values ) ) { throw new Error ( `Provided a non-array value to select[multiple]: ${ values }` ) ; } this . selectedIds = values . map ( value => this . getOptionId ( value ) ) . filter ( ( id ) : id is string => id !== null ) ; this . options . forEach ( ( option , id ) => option . selected = this . selectedIds . includes ( id ) ) ; } public registerOnChange ( fn ) { this . fnChange = fn ; } public registerOnTouched ( fn ) { this . fnTouched = fn ; } public setDisabledState ( isDisabled ) { this . renderer . setProperty ( this . elementRef . nativeElement , 'disabled' , isDisabled ) ; } public registerOption ( option ) { const newId = ( this . idCounter ++ ) . toString ( ) ; this . options . set ( newId , option ) ; return newId ; } public deregisterOption ( id ) { this . optionMap . delete ( id ) ; } public updateOptionValue ( id , value ) { this . optionMap . set ( id , value ) ; if ( this . selectedIds . includes ( id ) ) { this . onChange ( ) ; } } private getOptionId ( value ) { for ( const id of Array . from ( this . optionMap . keys ( ) ) ) { if ( this . optionMap . get ( id ) === value ) { return id ; } } return null ; } }