My problem is that I am updating options for a autocomplete input field based off the user's input. If the user has typed at least three characters in the textbox and the user hasn't typed in the last half second, I'll make an API call based off the input. Basically I want to recreate the autocomplete overview from here: https://material.angular.io/components/autocomplete/examples#autocomplete-filter
But instead of hard-coded values, I want the values to be dynamically changing as the user types. Now to my problem, once I have at least three characters and I stop typing, I receive the information and put it into my options array, but it doesn't get shown in the textbox until I update the field again by typing or backspacing. filteredOptions is the actual array being displayed to the user.
Code
TS
filteredOptions?: Observable<any[]>
options: any[] = []
localForm!: FormGroup
// Component Stuff
async ngOnInit() {
this.localForm = this.fb.group({
search: ['']
})
this.localForm.get('search')?.valueChanges.subscribe(() => onChangeTimeout())
this.subscribeToChanges()
}
onChangeTimeout() {
clearTimeout(this.timer);
this.timer = setTimeout(this.inputHandler.bind(this), 500)
}
async inputHandler() {
if (this.localForm.get('search')?.value !== null && this.localForm.get('search')?.value !== '') {
if (this.localForm.get('search')?.value.length >= 3) {
// API CALL THAT RESETS options AND THEN PUSHES ALL RECORDS FROM CALL INTO options
await this.getEmployeeInformation()
}
}
}
private subscribeToChanges() {
if (this.localForm.get('search')?.value !== null) {
this.filteredOptions = this.localForm.get('search')?.valueChanges.pipe(startWith(''), map((value) => this._filter(value)))
}
}
private _filter(value: any): any[] {
if (value !== null) {
const filterValue = this.toTitleCase(value)
return this.options?.filter((option) => this.toTitleCase(option.lastName).includes(filterValue))
} else {
return []
}
}
toTitleCase(str: string) {
return str.replace(
/\w\S*/g,
txt => ( txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase())
)
}
HTML
<form [formGroup]="localForm" (ngSubmit)="NA">
<mat-form-field class="form-field" appearance="outline">
<mat-label>Search By Last Name (BMCD EOs)</mat-label>
<input matInput type="text" placeholder="Testing" autocomplete="off" name="search"
formControlName="search" [matAutocomplete]="auto">
<mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
<mat-option *ngFor="let option of filteredOptions | async" [value]="option.fullName">
{{ option.fullName }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>