Reputation: 393
I am working on creating a Custom Form Control with a Typeahead input field in Angular. I want to call the _onChange function whenever the input changes. However, when I log the _onChange function, I see that it is never called, even though I'm making changes in the input field. Here is my TS file:
import { Component, EventEmitter, forwardRef, Input, Output, ViewChild } from '@angular/core';
import { AbstractControl, ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { NgbTypeahead } from '@ng-bootstrap/ng-bootstrap';
import { debounceTime, distinctUntilChanged, filter, map, merge, Observable, Subject } from 'rxjs';
@Component({
selector: 'app-typeahead-input',
templateUrl: './typeahead-input.component.html',
styleUrl: './typeahead-input.component.scss',
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: forwardRef(() => TypeaheadInputComponent),
},
],
})
export class TypeaheadInputComponent implements ControlValueAccessor {
@Input() placeholder: string;
@Input() dataSource: any[];
@Input() formatter: (item: any) => string;
@Input() abstractControl: AbstractControl<any, any>;
@Input() selectOnExact: boolean;
@Input() editable: boolean;
@ViewChild('instance', { static: true }) instance: NgbTypeahead;
focus$ = new Subject<string>();
click$ = new Subject<string>();
search: (text$: Observable<string>) => Observable<any[]> = (text$: Observable<string>) => {
const debouncedText$ = text$.pipe(debounceTime(200), distinctUntilChanged());
const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen()));
const inputFocus$ = this.focus$;
return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$).pipe(
map(term =>
term === ''
? this.dataSource
: this.dataSource
.filter(
(item: any) =>
this.formatter(item)
.toLowerCase()
.indexOf((term as string).toLowerCase()) > -1
)
.slice(0, 10)
)
);
};
_value: any;
_onChange = value => {};
_onTouched = () => {};
registerOnChange(fn: any): void {
this._onChange = value => {
console.log('Current value: ' + this._value);
fn(value);
};
}
registerOnTouched(fn: any): void {
this._onTouched = fn;
}
writeValue(obj: any): void {
console.log(obj);
this._value = obj;
}
}
and my HTML file:
<input
type="text"
class="form-control"
id="formControlName"
[value]="_value"
(change)="_onChange(_value)"
[placeholder]="placeholder"
[ngbTypeahead]="search"
[inputFormatter]="formatter"
[resultFormatter]="formatter"
#instance="ngbTypeahead"
(focus)="focus$.next($any($event).target.value)"
(click)="click$.next($any($event).target.value)"
[class.is-invalid]="abstractControl.invalid && (abstractControl.dirty || abstractControl.touched)"
[class.is-valid]="abstractControl.valid"
[editable]="editable"
[selectOnExact]="selectOnExact" />
<div class="invalid-feedback" *ngIf="abstractControl.invalid && (abstractControl.dirty || abstractControl.touched)">
<span *ngIf="abstractControl.errors">{{ placeholder }} muss gesetzt sein.</span>
</div>
Upvotes: 0
Views: 75