question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Autocomplete with multiple selection (MdAutocompleteTrigger customization)

See original GitHub issue

Feature proposal:

It would be nice if MdAutocomplete and MdAutocompleteTrigger supported the multiple attribute similar to MdSelect, or at least configuration options that make creating your own easier.

What is the expected behavior?

It should be possible to create an Autocomplete with multiple selection.

What is the current behavior?

MdAutocompleteTrigger is coded to assume single selection and is not easily customized, which makes a custom multi-autocomplete difficult to develop. Currently, you must “monkey-patch” private methods in MdAutocompleteTrigger.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

@angular/cli: 1.0.4 node: 6.9.1 os: linux x64 @angular/common: 4.2.0 @angular/material: 2.0.0-beta.6-f89c6db @angular/cli: 1.0.4

Is there anything else we should know?

Here are my notes on the major issues I encountered in developing my own multiple Autocomplete.

In ngAfterContentInit, I “monkey-patch” MdAutocompleteTrigger. You cannot extend MdAutocompleteTrigger because these methods are private.

The objective here is to:

  1. not deselect other MdOptions on selection
  2. leave the Autocomplete open after option selection event.

EDIT updated for beta12

if (this.multiple) {
      const self = this;

      /*
      easiest to just modify this MatAutoTrigger instance to get the behavior we want.
      Hopefully, material2 will support this in the future
       */
      const autoTrigger: any = this.mdAutoTrigger as any;

      // make a no-op so other options aren't cleared when selecting an option
      autoTrigger._clearPreviousSelectedOption = () => {};

      // need to override to continue getting these events
      // copied from material2/src/lib/autocomplete/autocomplete-trigger.ts with CHANGEs
      autoTrigger._subscribeToClosingActions = function(this: any): Subscription {
        const firstStable = first.call(this._zone.onStable.asObservable());
        const optionChanges = RxChain.from(this.autocomplete.options.changes)
          .call(doOperator, () => this._positionStrategy.recalculateLastPosition())
          // Defer emitting to the stream until the next tick, because changing
          // bindings in here will cause "changed after checked" errors.
          .call(delay, 0)
          .result();

        // When the zone is stable initially, and when the option list changes...
        return RxChain.from(merge(firstStable, optionChanges))
          // create a new stream of panelClosingActions, replacing any previous streams
          // that were created, and flatten it so our stream only emits closing events...
          .call(switchMap, () => {
            this._resetActiveItem();
            this.autocomplete._setVisibility();
            return this.panelClosingActions;
          })
          // when the first closing event occurs...
          // CHANGE disable first() because we want to continue getting events
          // .call(first)
          // set the value, close the panel, and complete.
          .subscribe(event => this._setValueAndClose(event));
      };

      // prevent closing on select option event
      autoTrigger._setValueAndClose = function(this: any, event: MatOptionSelectionChange | null): void {
        if (event && event.source) {
          // CHANGE don't clear selection, clear input, or change focus
          // this._clearPreviousSelectedOption(event.source);
          // this._setTriggerValue(event.source.value);
          this._onChange(event.source.value);
          // this._element.nativeElement.focus();
          this.autocomplete._emitSelectEvent(event.source);
        }
        // CHANGE added else clause (close non-MatOptionSelectionChange event)
        else {
          // NOTE this is the Subscription returned from _subscribeToClosingActions
          // CHANGE unsubscribe from the Subscription created in _subscribeToClosingActions
          this._closingActionsSubscription.unsubscribe();
          this.closePanel();
          // CHANGE clear input so placeholder can show selected values
          self.clearInput();
        }
      };

    }

Also, while working on this, I noticed that the code I was writing was very similar to MdSelect and most of the logic is in MdAutocompleteTrigger. So maybe what’s needed is a new MdMultiAutocompleteTrigger, which uses the same SelectionModel system that MdSelect uses.

The one other issue is that even with ngFor trackBy sometimes MdOption instances lose their selected state. So every time the options are filtered, I double-check MdOption.selected and select() deselect() as necessary.

Also, the way MdSelect sets MdOption.multiple seems awkward, but I basically do the same thing as the MdSelect code.

FYI, my solution for displaying multiple values is just to clear the input, floatPlaceholder=‘never’ and set placeholder to the displayWith() of each selected value separated by commas. This works fairly well. I also added a tooltip with the same content in case the entire text is not visible.

Issue Analytics

  • State:open
  • Created 6 years ago
  • Reactions:35
  • Comments:14 (3 by maintainers)

github_iconTop GitHub Comments

22reactions
sandeeppatidar30commented, Oct 17, 2018

This is how i implemented https://stackblitz.com/edit/angular-xgtey4 using mat-chips, mat-autocomplete. Using above approach there is a flicker in autocomplete panel while selecting multiple items so i have used another approach https://stackblitz.com/edit/angular-ah51ss where i used mat-select-list in autocomplete instead of mat-option

21reactions
bharathmuppacommented, Oct 3, 2017

It is good to have functionality especially in corporate application where there is always a need of this component

Read more comments on GitHub >

github_iconTop Results From Across the Web

Keep autocomplete suggestion panel open for multiple ...
M able to keep Panel open via MdAutocompleteTrigger event and openPanel method but what happens is if 2nd index is selected and m...
Read more >
Angular material multi-select with autocomplete - Medium
This document is about my open source component mat-select-autocomplete. mat-select-autocomplete gives feature of autocomplete on top of ...
Read more >
material 2 Autocomplete: select option - Stack Overflow
I want to call a function when an option is selected. After some search it seem that i have to use : property...
Read more >
Autocomplete | Angular Material
API reference for Angular Material autocomplete ... Whether the active option should be selected as the user is navigating. @Input('class').
Read more >
Elegant Multi-Select Component With Autocomplete - CSS Script
example", { options: myOptions, icon: "fa fa-times" // uses Font Awesome inlineIcon: false // custom cross icon for multiple select. }); Execute a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found