Anytime I select an option from Material Autocomplete, it makes an additional HTTP GET call to the server. The desired result of selecting a dropdown option should just be to populate the input.
The dropdown options are retrieved dynamically from the server.
HTML:
<form class="example-form">
<mat-form-field class="example-full-width">
<input type="text" placeholder="search item" aria-label="Item1" matInput [formControl]="searchTerm" [matAutocomplete]="auto1">
<mat-autocomplete #auto1="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let item of searchResult" [value]="item.Id">
{{ item.Name }}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>
TypeScript:
searchTerm : FormControl = new FormControl();
searchResult = [];
constructor(private service: AppService){
this.searchTerm.valueChanges
.debounceTime(400)
.subscribe(data => {
this.service.search_word(data).subscribe(response =>{
this.searchResult = response
})
Everything else works fine. The only issue is the unexpected extra call to the server when the autocomplete option is selected.
QUICK UPDATE: No answer has totally solved this yet. However, I have narrowed this down to possibly be a problem with displayWith.
Your issue is occurring because the dropdown selection changes the value of the searchTerm
form control; thus emitting an event for the valueChanges
observable on that form control.
There are a few ways to build some logic into your valueChanges
observable on the form control in order to ignore this unwanted Http GET request.
Naive solution
The naive solution is to store the dropdown option selection value and skip the observable logic if the selectionValue === searchTerm.value
.
var optionSelection; // set this value on selection of a dropdown option
this.searchTerm.valueChanges
.debounceTime(400)
.subscribe(data => {
if (optionSelection !== searchTerm.value) {
this.service.search_word(data).subscribe(response =>{
this.searchResult = response
})
}
})
Better Solution
The FormControl class has a setValue
function, which has an optional parameter to specify whether or not to emit an event to the valueChanges
observable.
setValue(value: any, options: {
onlySelf?: boolean;
emitEvent?: boolean;
emitModelToViewChange?: boolean;
emitViewToModelChange?: boolean;
} = {}): void
By changing your dropdown option selection to set the searchTerm form control value with setValue
, you can pass the optional emitEvent: false
parameter and stop this additional observable event from emitting.
searchTerm.setValue(dropdownValue, { emitEvent: false });
If emitEvent is false, this change will cause a valueChanges event on the FormControl to not be emitted. This defaults to true (as it falls through to updateValueAndValidity).
The problem lies in the amount of event that are tiggered there are two... I already made a bug for it's but it's how it supposed to work. Hope this will help.
This is my solution:
Html:
<mat-option *ngFor="let item of searchResult" [value]="item.Id" (onSelectionChange)="onSelectionChange($event, item.Id)"> // or item
In your component:
private onSelectionChange(_event: any, _id: any) {
if (_event.isUserInput === true) { // there are two events one with true and one with false;
this.service.search_word(_id).subscribe(response =>{
this.searchResult = response
})
}
you can use (keyup)="onKeyUp($event)"
in your input text and you can use it like this
onKeyUp(event: any) {
this.service.search_word(event.target.value).subscribe(response =>{
this.searchResult = response
})
}
As of Angular Material version 7.2.0 you have a new EventEmitter called 'optionSelected', for MatAutocomplete
So your HTML would be something like this:
<mat-autocomplete (optionSelected)="optionSelected($event)" #auto1="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let item of searchResult" [value]="item.Id">
{{ item.Name }}
</mat-option>
</mat-autocomplete>
And your .ts:
private optionSelected(event) {
console.log(event)
}
And you would handle it inside of optionSelected()
method.
Give it a try as I don't have all your code. And let me know if it doesn't work.
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