How to stop Material dropdown autocomplete selection from triggering another search query in Angular 8/9?

I've faced the same issue some time ago, and this is the final solution that I've been using for several inputs in my system.

The steps are:

  1. Realize that there are actually two events here. Something Typed and Value Selected.
  2. Create two observables for the the two events and handle them separately.
class Component {
  ngOnInit() {

    /*       SEPARATE THE EVENTS      */

    // If it's an object, it's been selected.
    // I also don't allow selecting `null` but it's up to you.
    const itemSelected$ = this.myForm.get('itemName').valueChanges.pipe(
      filter(val => typeof val === 'object' && val !== null),
    );
    // If it's a string, it's been typed into the input
    const itemTyped$ = this.myForm.get('itemName').valueChanges.pipe(
      filter(val => typeof val === 'string'),
    );

    /*       HANDLE ITEM SELECTED     */

    itemSelected$.subscribe(item => {
      // If you want, you can also handle "fake" items here.
      // I use this trick to show a placeholder like "Create New Item" in the dropdown
      if (item.id === 0 && item.name === 'Create New Item') {
        this.createNewItem().subscribe(
          newItem => this.myForm.get('itemName').setValue(newItem),
        );
        return;
      }
      // I use this in a custom input component (with ControlValueAccessor)
      // So this is where I notify the parent
      this.onChange(item);
    });

    /*       HANDLE ITEM TYPED        */

    const searchQueryResult$ = itemTyped$.pipe(
      debounce(200),
      tap(value => {/* you could handle starting a loading spinner or smth here */}),
      switchMap(name => this.appServiceItem.search({name}, 1)),
    );

    // now you can either use searchQueryResult$ with async pipe:
    // this.filteredResults$ = searchQueryResult$;
    // or subscribe to it and update a field in your component class:
    searchQueryResult$.subscribe(result => this.searchQueryResult = result);
    // If you subscribe, don't forget to clean up subscriptions onDestroy
  }
}

I've taken the liberty to add a few suggestions and tricks, but you get the general idea - create two separate mutually exclusive observables and handle them separately.


Made a simple app in Stackblitz, you can check it out. Hope I understood correctly your issue.

Main idea is - when user fills in form input we get string, when autocomplete fills it we get ItemUnit. This way we can decide whether to make http request or not.