import { ChangeDetectionStrategy , Component , ContentChild , EventEmitter , Input , OnInit , Output , TemplateRef , ViewChild } from '@angular/core' ; import { MatInput } from '@angular/material/input' ; import { MatListOption } from '@angular/material/list' ; import { BehaviorSubject , Observable } from 'rxjs' ; import { map } from 'rxjs/operators' ; export interface SelectListItem { key : string ; text : string ; selected : boolean ; } @ Component ( { selector : 'app-select-list' , templateUrl : './select-list.component.html' , styleUrls : [ './select-list.component.scss' ] , changeDetection : ChangeDetectionStrategy . OnPush } ) export class SelectListComponent implements OnInit { private items$ = new BehaviorSubject < SelectListItem [ ] > ( [ ] ) ; private _items : SelectListItem [ ] ; @ Input ( ) public set items ( items ) { this . _items = items ; this . filterItems ( ) ; } @ Output ( ) public itemsChange = new EventEmitter < SelectListItem [ ] > ( ) ; @ ContentChild ( TemplateRef , { static : true } ) public itemTemplate : TemplateRef < any > ; @ ViewChild ( MatInput , { static : true } ) public filter : MatInput ; public selected$ : Observable < SelectListItem [ ] > ; public deselected$ : Observable < SelectListItem [ ] > ; public trackByKey = ( _ , item ) => item . key ; public ngOnInit ( ) { this . selected$ = this . items$ . pipe ( map ( x => x . filter ( y => ! ! y . selected ) ) ) ; this . deselected$ = this . items$ . pipe ( map ( x => x . filter ( y => ! y . selected ) ) ) ; this . filterItems ( ) ; } public onFilterKeyUp ( ) { this . filterItems ( ) ; } public selectOptions ( options ) { if ( options . length > 0 ) { options . forEach ( option => option . value . selected = true ) ; this . updateItems ( ) ; } } public deselectOptions ( options ) { if ( options . length > 0 ) { options . forEach ( option => option . value . selected = false ) ; this . updateItems ( ) ; } } public selectItem ( item ) { item . selected = true ; this . updateItems ( ) ; } public deselectItem ( item ) { item . selected = false ; this . updateItems ( ) ; } private filterItems ( ) { const filterValue = ( this . filter . value || '' ) . toLowerCase ( ) ; this . items$ . next ( this . _items . filter ( item => { const itemValue = item . text . toLowerCase ( ) ; return itemValue . indexOf ( filterValue ) !== - 1 ; } ) ) ; } private updateItems ( ) { this . filterItems ( ) ; this . itemsChange . next ( this . _items ) ; } }