Use the mat-autocomplete filter to emphasize partial string matches in the search results

Is there a way to achieve a filter using mat-autocomplete similar to the one shown in this example:

trade input example

I am looking to implement functionality where as users type in the trade they are searching for, filters are applied based on partial string matches anywhere in the text and these matches are highlighted in the options.

https://i.sstatic.net/5LDEK.png

This is what I currently have in my .html file:

<mat-form-field class="form-group special-input">
            <input type="text" placeholder="Select a trade" aria-label="Select a trade" matInput [formControl]="categoriesCtrl" [matAutocomplete]="auto">
            <mat-autocomplete #auto="matAutocomplete" md-menu-class="autocomplete">
                <mat-option *ngFor="let option of filteredOptions | async" [value]="option.name">
                    {{ option.name }} 
                </mat-option>
            </mat-autocomplete>
        </mat-form-field>

And here's my .ts file:

categoriesCtrl: FormControl;

filteredOptions: Observable<ICategory[]>;
options: ICategory[];

categorySubscription: Subscription;

constructor(fb: FormBuilder, private router: Router, private service: SearchService, private http: Http) {

    this.categoriesCtrl = new FormControl();
}

ngOnInit() {

this.categorySubscription = this.service.getCategories().subscribe((categories: ICategory[]) => {

    this.options = categories;

    this.filteredOptions = this.categoriesCtrl.valueChanges
        .pipe(
        startWith(''),
        map(options => options ? this.filter(options) : this.options.slice())
        );
});    
}

ngOnDestroy() {
    this.categorySubscription.unsubscribe();
}

filter(val: string): ICategory[] {

    return this.options.filter(x =>
        x.name.toUpperCase().indexOf(val.toUpperCase()) !== -1);
}

The ICategory interface is basic:

export interface ICategory {
    value: number;
    name: string;  
}

The service getCategories() simply fetches all the categories from an API.

The current code functions properly and has been built following this example:

Angular Material mat-autocomplete example

Would it be possible to highlight the matching terms within the option strings? Is there a way to accomplish this?

Answer №1

A custom pipe can be utilized to emphasize the partial match when a user enters text in the filter field.

@Pipe({ name: 'highlight' })
export class HighlightPipe implements PipeTransform {
  transform(inputText: string, searchTerm): string {
    const pattern = searchTerm
      .replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&")
      .split(' ')
      .filter(word => word.length > 0)
      .join('|');
    const regex = new RegExp(pattern, 'gi');

    return searchTerm ? inputText.replace(regex, matchedWord => `<b>${matchedWord}</b>`) : inputText;
  }
}

Live Demo

Answer №2

If you encounter an undefined situation, the best approach is to verify the presence of the search string. There are instances where the control may not have any:

export class HighlightPipe implements PipeTransform {
  transform(text: string, search): string {
  if (search && text && typeof search === 'string' && typeof text === 'string') {
      const pattern = search
        .replace(/[\-\[\]\/{}()*x+?.\\^$|]/g, '\\$&')
        .split(' ')
        .filter(t => t.length > 0)
        .join('|');
      const regex = new RegExp(pattern, 'gi');
      return search ? text.replace(regex, match => `<strong>${match}</strong>`) : text;
    }
    return text;
  }
}

It's worth noting that some elements of the regex have been streamlined by removing unnecessary escapes.

When implementing this in your HTML code, make sure to utilize [innerHTML] instead of just piping the object text:

<mat-option [innerHTML]="optionText | highlight: searchValue"></mat-option>

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

Utilizing a personalized service within an extended RouterOutlet component in Angular 2 for streamlined authentication

In my quest to establish authentication in Angular 2, I turned to an insightful article (as well as a previous inquiry on SO) where I learned how to create a custom extended RouterOutlet: export class LoggedInRouterOutlet extends RouterOutlet { public ...

It appears that Yarn is having trouble properly retrieving all the necessary files for a package

Recently, I encountered a strange issue in our project involving 3 microservices, all using the exceljs library. Two of the microservices successfully download all necessary files for this package through yarn. However, the third microservice is missing ...

Could there be an issue with the way I've implemented my setInterval function?

I am currently in the process of developing a stopwatch feature using React Native and implementing the setInterval function to increase a counter and update the state accordingly: Play Function (triggered upon pressing the play button) const [isRunning ...

What is the best way to update a deeply nested array of objects?

I have an array of objects with nested data that includes product, task, instrument details, and assets. I am attempting to locate a specific instrument by supplier ID and modify its asset values based on a given number. const data = [ { // Data for ...

Methods for transforming a TypeScript class instance containing getter/setter properties into a JSON format for storage within a MySQL database

I am currently working on a TypeScript class that includes a getter and setter method: export class KitSection { uid: string; order: number; set layout(layout: KitLayout) { this._layout = new KitLayout(layout); } get layout( ...

How can I display or hide a specific div when it is clicked?

I have a list of icons that look like this: <ul> <li [ngClass]="iconM ? 'active': 'notactive'" title="Kontakti"><span (click)="showHide = !showHide"><i class="fa fa-user"></i><i class="fa fa-angl ...

The type declaration for the Storage.prototype.setObject method

I'm facing a challenge in creating a d.ts file for the given DOM feature. Storage.prototype.setObject = function(key:string, value:any) { this.setItem(key, JSON.stringify(value)); } Storage.prototype.getObject = function(key:string) { var va ...

Setting up Firebase in an NX Workspace

Looking for a way to set up an Nx Workspace with Firebase that can deploy multiple applications within the monorepo. Ideal file structure would resemble something like this: https://i.sstatic.net/oKJrT.png To deploy the various applications, hoping to pas ...

Having difficulty retrieving form controls using array notation function

import { Component, OnInit } from '@angular/core'; import { GetTransactionService } from '../../../service/getTransaction/get-transaction.service'; import { Router, Routes, RouterModule } from '@angular/router'; import { FormB ...

Unable to enclose an element with an HTML structure

I am attempting to take all the elements marked with the table tag and envelop them in an HTML structure to make the tables responsive. However, it appears that my current approach is not yielding the desired results. Can you please provide some insight ...

tips for preventing issues when the data array is empty

Here is the JSON data that I am dealing with: { "id": 43, "dataEvento": "2022-09-01T00:00:00.000+0000", "dataInvio": null, "idComunicazioneAssociata": null, "certificatoMedico" ...

Is it possible to eradicate arrow functions in Angular CLI?

I am facing a challenge in running my code on IE11 due to issues with arrow functions. I need to find a way to eliminate them from the build and replace them with function() {}. Even though I have removed them from main.js, they are still present in the v ...

`How can I transform a DocumentSnapshot.data() object into a Map using TypeScript and Firestore?`

Currently working on an Angular Ionic project with Firestore and encountering a problem. Here is the code snippet that I am struggling with: handler: data => { firebase.firestore().collection("categories").doc(`${data.name}`).get() .then((ds) ...

Angular 2 gulp task for combining multiple scss files into a single css file

app -file1 -- file1.ts -- file1.html -- file1.scss -file2 -- file2.ts -- file2.html -- file2.scss -file3 -- file3.ts -- file3.html -- file3.scss This is the structure of my project. I am currently working on consolidating all my scss files in ...

Is there a ReactNode but with greater specificity?

In setting up the properties for a component, I have defined them as follows: interface HeaderProps{ title: string; image: string; link: ReactNode; } The 'link' property is meant to refer to another component, specifically <Link /> ...

Display full lines of nested tree view HTML lists upon hovering using HTML, CSS, Angular, and Bootstrap

I currently have an Angular 4 application where a left-side div displays a tree of items as recursive HTML lists. The issue I am facing is that long texts within this div get cut off by the right border, with a scrollbar appearing instead. What I would lik ...

Having trouble retrieving documents from a nested collection in Firebase

I am attempting to retrieve all documents from Firebase that are based on a query. Here is my current firebase structure: https://i.stack.imgur.com/tXrX8.png Even though I have two documents inside the "ListaFavorite" collection, when I check using empty ...

Steps to deactivate an angular material component on version 2.0.0-beta.5

Recent updates have led to an error in my code: Error at /Users/asaylor/Desktop/RevenueIQ/website/aot/node_modules/@angular/material/typings/index.ngfactory.ts:4236:30: Property 'disabled' does not exist on type 'MdCheckbox' I am enc ...

Tips for deploying an Angular 2+ application on the OpenShift platform

I successfully developed an Angular application on my Windows PC, and now I am facing challenges in deploying it on Red Hat OpenShift. Despite searching for guides online, I have not been able to find helpful resources. If anyone has experience with deploy ...

Creating a WebExtension using Angular and TypeScript

I am currently working on creating a WebExtension using Angular and Ionic. The extension successfully loads the application and enables communication between Content Script and Background Script. However, I am facing an issue where the TypeScript code is n ...