I am using this link for implementing a Typeahead. Now I am using TypeaheadOptionField to display a name on typeahead but it also binds the name string in the model. I want to bind the Object instead of the string.
My HTML Code:
<input formControlName="item" class="form-control" [typeahead]="allItemsArray" [typeaheadItemTemplate]="customItemTemplate"
[typeaheadOptionsLimit]="7" [typeaheadMinLength]="0" [typeaheadOptionField]="name" (typeaheadOnSelect)="onSelectItem($event)">
allItemsArray:
[
{
name: 'a',
code: '12'
},
{
name: 'b',
code: '13'
}
]
Value bound to form control: 'a'
Required value: {'name': 'a', 'code': '12'}
One thing I tried is implementing an event which sets the model value as object but it didn't work.
I'm having the exact same problem right now.
When the typeahead is used with the Angular Form API, it uses the value found for the key passed in typeaheadOptionField
. This is imho a bug or at least it should be configurable.
What I'm doing now is wrapping the input with a custom control and using the Output typeaheadOnSelect
which is called when an option of the typeahead is selected. Within the event data you can find the entire object. But you have to handle the control data management by yourself.
At least for now, I couldn't find another solution.
Edit:
Here's my code (removed all abstractions, no warranty that it works):
@Component({
selector: 'my-typeahead-control',
templateUrl: './my-typeahead-control.html',
providers: [
{provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => MyTypeaheadControl), multi: true}
]
})
export class MyTypeaheadControl implements ControlValueAccessor
{
// -- -- -- -- -- -- -- -- -- -- typeahead data -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
@Input()
public items:any[] | Observable<any[]> = [];
@Input()
public itemLabelKey:string;
// -- -- -- -- -- -- -- -- -- -- internal data -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
public selectedItemLabel:string;
// -- -- -- -- -- -- -- -- -- -- interface implementation -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
public writeValue(obj:any):void
{
this.updateSelectedItemLabel(obj);
}
private onChange:Function;
public registerOnChange(fn:any):void
{
this.onChange = fn;
}
private onTouch:Function;
public registerOnTouched(fn:any):void
{
this.onTouch = fn;
}
public setDisabledState(isDisabled:boolean):void
{
// ...
}
// -- -- -- -- -- -- -- -- -- -- control data handling -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
public onSelect(event:TypeaheadMatch):void
{
this.onTouch();
this.onChange(event.item);
this.updateSelectedItemLabel(event.item);
}
private updateSelectedItemLabel(obj:any):void
{
this.selectedItemLabel = (this.itemLabelKey) ? _.get(obj, this.itemLabelKey) : obj;
}
}
And the template:
<input [ngModel]="selectedItemLabel"
[typeahead]="items"
[typeaheadOptionField]="itemLabelKey"
[typeaheadMinLength]="0"
[container]="'body'"
(typeaheadOnSelect)="onSelect($event)">
Now it can be used as follows:
<my-typeahead-control formControlName="item" [items]="allItemsArray" itemLabelKey="name"></my-typeahead-control>
Here's basically how I worked around this problem with Angular 7 and NGX-Bootstrap 3.
HTML
<input
[formControl]="myTypeahead"
[typeahead]="filteredOpts"
typeaheadOptionField="value"
(typeaheadOnSelect)="select($event.item)"/>
TypeScript
interface Opt {
value: string;
key: string;
}
export class MyComp implements OnInit {
myTypeahead = new FormControl();
options: Opts[];
filteredOpts: Opts[] = [];
selectedOption: Opt;
constructor() {}
ngOnInit() {
this.myTypeahead.valueChanges.pipe(startWith(''))
.subscribe((value) => {
this.filteredOpts = this._filter(value));
}
private _filter(value: string): Opt[] {
return this.options
.filter((opt: Opt) => opt.value.toLowerCase().includes(value.toLowerCase()));
}
select(opt: Opt) {
this.selectedOption = opt;
}
}
Based on the Angular Material Autocomplete custom filter example found here: https://material.angular.io/components/autocomplete/overview
My case was slightly more complicated in that I was loading options
with an API call in ngOnInit
, but that was no issue.
Also note that this is basically doing the work of the typeahead in _filter
and is not the most efficient method. However it got me moving forward again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With