import {Component, forwardRef, Input, OnInit, ViewChild} from '@angular/core'; import {AuthService} from '../service/auth.service'; import { debounce } from 'ts-debounce'; import {PeopleModel} from '../models/people.model'; import {ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR} from '@angular/forms'; import {MultiColumnComboBoxComponent} from '@progress/kendo-angular-dropdowns'; import {Observable} from 'rxjs'; import {PeopleService} from '../service/people.service'; @Component({ selector: 'app-people-select', templateUrl: './people-select.component.html', styleUrls: ['./people-select.component.scss'], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => PeopleSelectComponent), multi: true } ] }) export class PeopleSelectComponent implements OnInit, ControlValueAccessor { @Input() disabled = false; @Input() translateId: true; // always tralsnate user Id, because name is not unique @Input() width: number; @Input() initSearch: PeopleModel[]; @Input() formControl: FormControl = new FormControl(); // this is a dummy place holder @ViewChild('list', {static: true}) public text: MultiColumnComboBoxComponent; public searchResult: PeopleModel[] = []; public value = ''; // selecting the default and only empty contact element // TODO: remove ngModel public total = 0; private debounceFilter: any ; // Function to call when the rating changes. private onChange = ( nameOrId: string) => {}; // Function to call when the input is touched (when a star is clicked). private onTouched = () => {}; constructor(private auth: AuthService, private ps: PeopleService) { } ngOnInit(): void { this.prepareSearchPeople(); this.initSearchResult(); } private initSearchResult(): void { this.initSearch.forEach( v => { this.searchResult.push(v); }); this.total = this.initSearch.length; } private prepareSearchPeople(): void{ this.debounceFilter = debounce( (filter: string): void => { this.ps.getPeopleList(filter).subscribe( resp => { this.text.loading = false; this.searchResult = resp.List; this.total = resp.Count; }, error => { this.text.loading = false; }, () => { this.text.loading = false; } ); }, 500) ; } getEffectiveField(): string { return this.translateId ? 'Id' : 'Display'; } filterChange(filter: string): void { if ( filter.length > 0 ) { this.text.loading = true; this.debounceFilter(filter); // conduct search even if filter is empty } } public getContactImageUrl(contactId: string): string { return this.auth.getUrl('avatar/' + contactId); } // ComboBox emit event on value change public valueChange(str: string): void { return; console.log('value change', str); this.onChange(this.value); } // public selectionChange(value: PeopleModel): void { // this.onTouched(); // console.log('selectionChange', value); // this.value = this.translateId ? value.Id : value.FullName; // this.onChange(this.value); // } // public open(): void { // this.onTouched(); // // console.log('open', this.text); // } // // public close(): void { // this.onTouched(); // // console.log('close', this.text); // } // // public focus(): void { // this.onTouched(); // // console.log('focus', this.text); // } // // public blur(): void { // // console.log('blur', this.text); // } // Allows Angular to update the model (name or ID). // Update the model and changes needed for the view here. writeValue(nameOrId: string): void { if ( nameOrId === undefined ){ console.log('who called me for write', this); return; } const changed = nameOrId !== this.value; if (this.needSearch(nameOrId) ){ this.text.loading = true; console.log('searching ... ', nameOrId, this.translateId ? 'by id' : 'by name'); this.searchUser(nameOrId, this.translateId).subscribe( ppl => { const person = new PeopleModel(ppl); console.log('got search result ', person); this.searchResult.push(person); // make sure it's available for selection, thus proper display this.value = this.translateId ? person.Id : person.FullName; console.log('before update', this.text.value); this.text.value = this.value; console.log('after update', this.text.value); }, error => { console.error(error); this.text.loading = false; }, () => {this.text.loading = false; } ); if ( changed ) { this.onChange(nameOrId); } } } needSearch(incoming: string ): boolean { if ( incoming === undefined || incoming === '' || incoming === this.value ) { return false; } const idx = this.searchResult.findIndex( person => { if ( this.translateId) { return person.Id === incoming; }else{ return person.FullName.includes(incoming); } }); return idx === -1; // not found need search } // Search a user either based on partial name or a complete ID searchUser(nameOrId: string, translateId: boolean): Observable{ if ( translateId ) { return this.ps.getPeopleById(nameOrId); // return this.searchPersonById( nameOrId) ; }else{ // return this.ps.searchById(nameOrId); // return this.searchPersonByName(nameOrId) ; } } // searchPersonByName(name: string): Observable{ // return new Observable ( observer => { // const dummy: PeopleModel = new PeopleModel( // 'dummy-id', // 'FSearch', // 'LResult', // '', // 'Mr.', // 'Display Name', // 'Nick Name' // ); // setTimeout(() => { // observer.next(dummy); // observer.complete(); // }, 1000); // }); // } // // searchPersonById( id: string): Observable { // return new Observable ( observer => { // const dummy: PeopleModel = new PeopleModel( // id, // 'FSearch', // 'LResult', // '', // 'Mr.', // 'P:' + id, // 'Nick Name' // ); // setTimeout(() => { // observer.next(dummy); // observer.complete(); // }, 1000); // }); // } // Allows Angular to register a function to call when the model (rating) changes. // Save the function as a property to call later here. registerOnChange(fn: (nameOrId: string) => void): void { this.onChange = fn; } // Allows Angular to register a function to call when the input has been touched. // Save the function as a property to call later here. registerOnTouched(fn: () => void): void { this.onTouched = fn; } // Allows Angular to disable the input. setDisabledState(isDisabled: boolean): void { this.disabled = isDisabled; } }