Can Autocomplete in Angular4+ support multiple selection options?

I am trying to implement a multi-selection feature on filtered items using an autocomplete function. I found inspiration from this tutorial and attempted the following code:

The component :

 <form class="example-form">
  <mat-form-field class="example-full-width">
    <input type="text" placeholder="Pick one" aria-label="Number" matInput [formControl]="myControl" [matAutocomplete]="auto">
    <mat-autocomplete #auto="matAutocomplete">
      <mat-option *ngFor="let option of filteredOptions | async" [value]="option" multiple>
      <mat-checkbox>
        {{ option }}
     </mat-checkbox> 
     </mat-option>
    </mat-autocomplete>
  </mat-form-field>
</form>

It seems that adding the 'multiple' attribute did not enable the selection functionality as expected. When I filter and select one option, the menu closes and the checkbox remains unchecked. Is there a workaround to implement multi-selection in Autocomplete successfully? Thank you for your help!

Answer №1

Explore Angular Material documentation for chips to find a helpful example on setting up a multiple selection autocomplete feature:

<mat-form-field class="example-chip-list">
  <mat-chip-list #chipList>
    <mat-chip
      *ngFor="let fruit of fruits"
      [selectable]="selectable"
      [removable]="removable"
      (removed)="remove(fruit)">
      {{fruit}}
      <mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
    </mat-chip>
    <input
      placeholder="New fruit..."
      #fruitInput
      [formControl]="fruitCtrl"
      [matAutocomplete]="auto"
      [matChipInputFor]="chipList"
      [matChipInputSeparatorKeyCodes]="separatorKeysCodes"
      [matChipInputAddOnBlur]="addOnBlur"
      (matChipInputTokenEnd)="add($event)">
  </mat-chip-list>
  <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
    <mat-option *ngFor="let fruit of filteredFruits | async" [value]="fruit">
      {{fruit}}
    </mat-option>
  </mat-autocomplete>
</mat-form-field>

In essence, this code snippet demonstrates a chip list linked to a list and a text input that enables searching through an autocomplete list.

import {COMMA, ENTER} from '@angular/cdk/keycodes';
import {Component, ElementRef, ViewChild} from '@angular/core';
import {FormControl} from '@angular/forms';
import {MatAutocompleteSelectedEvent, MatChipInputEvent} from '@angular/material';
import {Observable} from 'rxjs';
import {map, startWith} from 'rxjs/operators';

/**
 * @title Chips Autocomplete
 */
@Component({
  selector: 'chips-autocomplete-example',
  templateUrl: 'chips-autocomplete-example.html',
  styleUrls: ['chips-autocomplete-example.css'],
})
export class ChipsAutocompleteExample {
  visible = true;
  selectable = true;
  removable = true;
  addOnBlur = false;
  separatorKeysCodes: number[] = [ENTER, COMMA];
  fruitCtrl = new FormControl();
  filteredFruits: Observable<string[]>;
  fruits: string[] = ['Lemon'];
  allFruits: string[] = ['Apple', 'Lemon', 'Lime', 'Orange', 'Strawberry'];

  @ViewChild('fruitInput') fruitInput: ElementRef;

  constructor() {
    this.filteredFruits = this.fruitCtrl.valueChanges.pipe(
        startWith(null),
        map((fruit: string | null) => fruit ? this._filter(fruit) : this.allFruits.slice()));
  }

  add(event: MatChipInputEvent): void {
    const input = event.input;
    const value = event.value;

    // Add our fruit
    if ((value || '').trim()) {
      this.fruits.push(value.trim());
    }

    // Reset the input value
    if (input) {
      input.value = '';
    }

    this.fruitCtrl.setValue(null);
  }

  remove(fruit: string): void {
    const index = this.fruits.indexOf(fruit);

    if (index >= 0) {
      this.fruits.splice(index, 1);
    }
  }

  selected(event: MatAutocompleteSelectedEvent): void {
    this.fruits.push(event.option.viewValue);
    this.fruitInput.nativeElement.value = '';
    this.fruitCtrl.setValue(null);
  }

  private _filter(value: string): string[] {
    const filterValue = value.toLowerCase();

    return this.allFruits.filter(fruit => fruit.toLowerCase().indexOf(filterValue) === 0);
  }
}

This code offers straightforward functionality such as filtering based on the text input after each character is typed and removing items from the list. Feel free to customize it further according to your specific requirements (e.g., automatically excluding selected items from future autocomplete suggestions).

Answer №2

Although I'm a bit late to the party, I stumbled upon this fantastic stackBlitz here. Below is the code provided by the owner:

HTML:

<mat-form-field class="example-full-width">
    <input type="text" placeholder="Select Users" aria-label="Select Users" matInput [matAutocomplete]="auto" [formControl]="userControl">
  <mat-hint>Enter text to find users by name</mat-hint>
</mat-form-field>

<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
    <mat-option *ngFor="let user of filteredUsers | async" [value]="selectedUsers">
        <div (click)="optionClicked($event, user)">
            <mat-checkbox [checked]="user.selected" (change)="toggleSelection(user)" (click)="$event.stopPropagation()">
                {{ user.firstname }} {{ user.lastname }}
            </mat-checkbox>
        </div>
    </mat-option>
</mat-autocomplete>

<br><br>

<label>Selected Users:</label>
<mat-list dense>
    <mat-list-item *ngIf="selectedUsers?.length === 0">(None)</mat-list-item>
    <mat-list-item *ngFor="let user of selectedUsers">
        {{ user.firstname }} {{ user.lastname }}
    </mat-list-item>
</mat-list>

Typescript:


import { Component, OnInit, ViewChild } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Observable } from 'rxjs';
import { map, startWith } from 'rxjs/operators';

export class User {
  constructor(public firstname: string, public lastname: string, public selected?: boolean) {
    if (selected === undefined) selected = false;
  }
}

/**
 * @title Multi-select autocomplete
 */
@Component({
  selector: 'multiselect-autocomplete-example',
  templateUrl: 'multiselect-autocomplete-example.html',
  styleUrls: ['multiselect-autocomplete-example.css']
})
export class MultiselectAutocompleteExample implements OnInit {

  userControl = new FormControl();

  users = [
    // List of users...
  ];

  selectedUsers: User[] = new Array<User>();

  filteredUsers: Observable<User[]>;
  lastFilter: string = '';

  ngOnInit() {
    this.filteredUsers = this.userControl.valueChanges.pipe(
      startWith<string | User[]>(''),
      map(value => typeof value === 'string' ? value : this.lastFilter),
      map(filter => this.filter(filter))
    );
  }

  filter(filter: string): User[] {
    // Filtering logic...
  }

  displayFn(value: User[] | string): string | undefined {
    // Display logic...
  }

  optionClicked(event: Event, user: User) {
    // Option clicked logic...
  }

  toggleSelection(user: User) {
    // Toggle selection logic...
  }

}


Answer №3

If you're looking for a recommendation, I would recommend utilizing Ng2-select:

   <ng-select [virtualScroll]="true" #select [items]="items" [multiple]="true" bindLabel="name" placeholder="items..."
          formControlName="myFormCOntrolName">
        </ng-select>

This library is designed with angular material styling. Although the virtualScroll feature may not be extensively documented at this time, it proves to be highly efficient when dealing with large data sets.

Answer №4

If you're looking for a multiple selection option, give Ng2-select a try. You can find it at this link. Feel free to test it out and see if it meets your needs.

When it comes to multiple selection features, finding a one-size-fits-all solution is often challenging.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Leverage the SVG foreignObject Tag within your Angular 7 project

I am currently working with Angular 7 and trying to use the SVG foreignObject to embed some HTML code. However, I am encountering an issue where Angular fails to recognize the HTML tags and throws an error in the terminal. Below is the code snippet: &l ...

Sort the ngFor Angular loop by the start_date

Within the select available date section, there is an array of dates like the one shown in the image https://i.sstatic.net/NjN36.png. The following code uses ngFor: <div *ngFor="let date of tripdetail.trip_availabledate; let i = index;"> <a [ ...

Trouble with Angular 7: Form field not displaying touched status

I am encountering an issue while trying to input data into a form, as it is not registering the touched status. Consequently, an error always occurs when attempting to send a message back to the user. In my TypeScript file, I am utilizing FormBuilder to c ...

Definition for TypeScript for an individual JavaScript document

I am currently attempting to integrate an Ionic2 app within a Movilizer HTML5 view. To facilitate communication between the Movilizer container client and the Ionic2 app, it is crucial to incorporate a plugins/Movilizer.js file. The functionality of this f ...

Compilation of various Typescript files into a single, encapsulated JavaScript bundle

After researching countless similar inquiries on this topic, I have come to the realization that most of the answers available are outdated or rely on discontinued NPM packages. Additionally, many solutions are based on packages with unresolved bug reports ...

Typescript: Utilizing method overloading techniques

I'm in the process of implementing function overloads that look like this: public groupBy(e: Expression<any>): T { e = this.convert(e, Role.GROUP_BY); this.metadata.addGroupBy(e); return this.self; } public grou ...

Tips for implementing JS function in Angular for a Collapsible Sidebar in your component.ts file

I am attempting to collapse a pre-existing Sidebar within an Angular project. The Sidebar is currently set up in the app.component.html file, but I want to transform it into its own component. My goal is to incorporate the following JS function into the s ...

Is there a way to identify and retrieve both the initial and final elements in React?

Having an issue with logging in and need to retrieve the first and last element: Below is my array of objects: 0: pointAmountMax: 99999 pointAmountMin: 1075 rateCode: ['INAINOW'] roomPoolCode: "ZZAO" [[Prototype]]: Object 1: pointAmoun ...

Exploring the capabilities of extending angular components through multiple inheritance

Two base classes are defined as follows: export class EmployeeSearch(){ constructor( public employeeService: EmployeeService, public mobileFormatPipe: MobileFormatPipe ) searchEmployeeById(); searchEmployeeByName(); } ...

Unable to retrieve a property from a variable with various data types

In my implementation, I have created a versatile type that can be either of another type or an interface, allowing me to utilize it in functions. type Value = string | number interface IUser { name: string, id: string } export type IGlobalUser = Value | IU ...

What are the steps to access a query parameter within an API route.js file using the latest App routing strategy?

Here is the goal I am aiming for: Utilize Next.js with App router. Establish a backend route /api/prompt?search=[search_text] Retrieve and interpret the search query parameter in my route.ts file. Based on the search parameter, send back data to the front ...

lint-staged executes various commands based on the specific folder

Within my project folder, I have organized the structure with two subfolders: frontend and backend to contain their respective codebases. Here is how the root folder is set up: - backend - package.json - other backend code files - frontend - p ...

Highlighting DOM elements that have recently been modified in Angular

Is there a simple way to change the style of an element when a bound property value changes, without storing a dedicated property in the component? The elements I want to highlight are input form elements: <tr field label="Lieu dépôt"> ...

Setting up an empty array as a field in Prisma initially will not function as intended

In my current project using React Typescript Next and prisma, I encountered an issue while trying to create a user with an initially empty array for the playlists field. Even though there were no errors shown, upon refreshing the database (mongodb), the pl ...

When TypeScript generator/yield is utilized in conjunction with Express, the retrieval of data would not

Trying to incorporate an ES6 generator into Express JS using TypeScript has been a bit of a challenge. After implementing the code snippet below, I noticed that the response does not get sent back as expected. I'm left wondering what could be missing: ...

Error: Invalid connection string for ELF Lambda detected

Having an issue with a lambda function that connects to a remote MongoDB on an EC2 instance using TypeScript. While I can connect to the database locally, there is an ELF error when running in lambda. It seems to be related to mismatched binaries of npm pa ...

Getting a file object with v-file-input in Nuxt.js

For my Nuxt.Js apps, I utilized Vuetify.js as the UI framework. In order to obtain the file object when uploading files, I incorporated the v-file-input component from Vuetify.js and wrote the following code snippet: <template> <div> ...

Steps for transferring .pem files to Typescript outDir

I am currently working on a NodeJS project using Typescript, and I have encountered an issue with referencing .pem files to initiate an https server. The problem arises when my code is compiled, as the .pem files are not present in the output directory. ...

Angular ngModel failing to accurately reflect changes in input value

I am facing an issue with implementing a smart number input component that can toggle between allowing or disallowing negative numbers. I have an event listener for the (input) on the <input> element, triggering a function that applies various regex ...

Creating a TypeScript shell command that can be installed globally and used portably

I am looking to create a command-line tool using TypeScript that can be accessed in the system's $PATH once installed. Here are my criteria: I should be able to run and test it from the project directory (e.g., yarn command, npm run command) It must ...