Adding a visible icon to an Angular Material dropdown: A step-by-step guide

Seeking help on integrating a clear icon to the right side of a dropdown (select component) in Angular Material, only visible when an option is selected by the user. When this "clear" icon is clicked, the value should be deleted and the field reset. I currently have the dropdown set up but struggling with displaying the icon correctly. Any guidance on how to achieve this would be greatly appreciated. Thank you!

Snippet of my code:

<mat-form-field appearance="fill">
  <mat-label>Select a food</mat-label>
  <mat-select>
    <mat-option *ngFor="let food of foods" [value]="food.value">
      {{food.viewValue}}
    </mat-option>
    <mat-select-trigger>
        <button>
           <mat-icon>clear</mat-icon>
       </button>
    </mat-select-trigger>
  </mat-select>
</mat-form-field>

Check out the LIVE DEMO

Answer №1

To enable two-way binding and add the selected value to mat-select, make sure to include ngModel on mat-select. Additionally, you can add a button as a suffix of mat-select.

<mat-select [(ngModel)]="selectedFood">
    <mat-option *ngFor="let food of foods" [value]="food.value">
        {{ food.viewValue }}
    </mat-option>
</mat-select>
<button mat-button matSuffix *ngIf="selectedFood" mat-icon-button (click)="onClick($event)">
    <mat-icon>close</mat-icon>
</button>

To clear the selected food value on the component side, add the following function:

onClick(event: any) {
    this.selectedFood = "";
    event.stopPropagation();
}

The use of event.stopPropagation() will prevent the mat select dropdown from opening when the clear button is clicked.

For a fully functional example, visit:

https://stackblitz.com/edit/angular-c7hgum-94nqyq

Answer №2

<div class="food-selection">
    <label>Choose your favorite food</label>
    <select [(ngModel)]="chosenFood">
        <option *ngFor="let item of menuItems" [value]="item.value">
            {{item.text}}
        </option>
    </select>
    <button *ngIf="chosenFood" (click)="clearSelection()">
        Clear Selection
    </button>
</div>

Answer №3

Here is THE SOLUTION that proved successful for me.... utilizing mat-select Within the component.ts file

import {Directive, HostListener} from "@angular/core";

@Directive({
    selector: "[click-stop-propagation]"
})
export class ClickStopPropagation
{
    @HostListener("click", ["$event"])
    public onClick(event: any): void
    {
        event.stopPropagation();
    }
}

To call the function in the template, use this syntax

(click)="onCLick($event)

Answer №4

One possible method to achieve this is:

HTML:

<ng-template #clearRef>
  @if (value) {
    <svg
      class="text-danger"
      xmlns="http://www.w3.org/2000/svg"
      width="20"
      height="20"
      (click)="$event.stopPropagation(); control.reset()"
    >
      <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
    </svg>
  }
</ng-template>

<ng-template #chevrondownRef>
  <svg class="chevron-down" [class.animate]="isPanelOpen" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
    <path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
  </svg>
</ng-template>

CSS:

.mat-mdc-form-field-type-mat-select {
  .mat-mdc-form-field-infix {
    --mat-form-field-container-vertical-padding: 0;

    .mat-mdc-select-arrow-wrapper {
      flex-direction: row-reverse;
      gap: 0.5rem;
    }
  }
}

.chevron-down {
  transition: all 0.25s ease;
  transform: translate(-50%, -50%) rotate(0deg);

  &.animate {
    transform: translate(-50%, -50%) rotate(180deg);
  }
}

TS:

  • including
    encapsulation: ViewEncapsulation.None,
  private vcr = inject(ViewContainerRef);

  @ViewChild(MatSelect) matSelect!: MatSelect;
  @ViewChild("clearRef") clearRef!: TemplateRef<HTMLElement>;
  @ViewChild("chevrondownRef") chevrondownRef!: TemplateRef<HTMLElement>;

  ngAfterViewInit(): void {
    //Called after ngAfterContentInit when the component's view has been initialized. Applies to components only.
    //Add 'implements AfterViewInit' to the class.
    const mdcSelectArrowWrapper = document.querySelector(".mat-mdc-select-arrow-wrapper");
    const mdcSelectArrow = this.matSelect._elementRef.nativeElement.querySelector(
      ".mat-mdc-select-arrow-wrapper .mat-mdc-select-arrow",
    ) as HTMLElement;

    mdcSelectArrowWrapper?.appendChild(this.vcr.createEmbeddedView(this.clearRef).rootNodes[0]);
    mdcSelectArrow.replaceChildren(this.vcr.createEmbeddedView(this.chevrondownRef).rootNodes[0]);
  }

Outcome: https://i.sstatic.net/LrQ4IMdr.png

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

What is the best way to display time instead of angles in highcharts?

Hey there! I'm currently working with highcharts and I have a polar chart where I want to display time on the y-axis instead of angles. Here's what I've tried so far: On the x-axis, I have angles and I've set tickInterval: 45,. How can ...

Checking for the existence of a date in an array and retrieving its corresponding ID using AngularJS

I need to find the ID associated with a specific date in an array. The code I have tried using includes() is not working as expected. const results = []; angular.forEach(getEventdate, function(value) { results.push({id:value.id,event_date:value.event_dat ...

Trouble with setInterval not refreshing the HTML element

I'm currently working on a script that should update the value of an element every second. However, I've encountered an issue where the element only updates the first time and then stops. Strangely, there are no errors appearing in the console ei ...

Leveraging *ngFor to extract HTML content from ion-label

I've encountered an issue while using *ngFor in my HTML like this: <ion-slides #slides [options]="slideOpts"> <ion-slide class="numbers-wrapper" *ngFor="let questionNumber of numbers" (click)="clickQue ...

Something went wrong with @wdio/runner: unable to establish session

After successfully developing cucumber tests that passed and tested some URLs with Chrome, I encountered errors when uploading to the pipeline despite the tests succeeding. Webdriver generated the following errors: INFO webdriver: DATA { 57[0-0] capabili ...

What is the best way to initiate actions once the form has been successfully processed?

Could someone assist me with creating a form that hides after submission and displays a thank you message instead? I've tried the code below, but it seems that the action isn't being executed once the form is submitted. It's as if the ' ...

Tips for creating a test to choose a movie from the MuiAutocomplete-root interface

I am currently utilizing Material UI with React using Typescript and I am looking to create a test for the autocomplete functionality using Cypress. Here is the approach I have taken: Identifying the Autocomplete component and opening it, Choosing an opti ...

Using Node.js with Express to seamlessly pass objects to EJS templates

I have a scenario where I am passing an object to my template and I want to display the details of that object in HTML. app.get('/', function (req, res) { var user = req.session.passport.user; if ( user != 'undefined' ){ ...

CustomTooltips in ChartJS allowing for an enhanced visual presentation of data

I am encountering an issue with my code where I am trying to incorporate images into custom tooltips. The goal is to dynamically generate PNG filenames based on the tooltip name or ID, but I am struggling to find unique values to assign as filenames for ea ...

Retrieving a pair of data points from a Vue <select> event when it changes

I am facing an issue with a dropdown menu that is using an array with key:value pairs. I want the dropdown to only show values, but when a selection is made, I need to pass both the value and the key using the @change event. <select @change=" ...

Tips for creating a fixed AppBar and table headers that are stacked underneath each other on a single page while scrolling, using Material UI

Check out these screenshots of the AppBar and Table: View screenshot at the top of the page. Screenshot when scrolling down Take a look at the code for the AppBar and Table: <AppBar position="static" style = {{background : "#00009A"}}> ...

Nesting divs that soar within a contained div (not spanning the entire page)

I need the div elements to move within another div container instead of flying over the entire page. What changes do I need to make in the code to achieve this? $(document).ready(function() { $('.balloon').each(animateDiv); }); function ma ...

Retrieving string-based JSON information

Within my text box, the user inputs strings separated by commas. These strings are split on the front end, then sent to the backend to retrieve data in JSON format. The interesting part is that when I directly entered the key of the JSON, like this, it wo ...

I am trying to locate the XPath for the NG repeat element with the following code snippet: ng-repeat="thread in threads | orderBy:'-last_ts' | filter : globalSearch track by $index" Can you assist

<div ng-click="changeChatThread(thread, true)" class="item ui three column grid thread_item ng-scope active-thread" ng-class="{'active-thread' : selectedThread === thread.chat_id}" ng-repeat="thread in threads | orderBy:'-last_ts' | ...

Utilizing Moment.js fromnow functionality with Vue.js and Laravel framework

Currently utilizing Laravel with Vue for my project Vue.http.headers.common['X-CSRF-TOKEN'] = $("#token").attr("value"); new Vue({ el: '#notificationMenu', data: { patients: [] }, ...

When I click on my div, the color does not change as expected

Recently, I wrote a code snippet where there are 9 different div elements each assigned a ".spaces" class. The intention was to change the color of these divs upon clicking on them. However, I encountered an issue where only the first div changes its color ...

"An ActionResult is received as null when the model is passed as an

Has anyone encountered a situation where the model is null when passed to the controller? I inserted an alert in the ajax call to verify the value and it seemed correct, but upon debugging on the first line of the controller's ActionResult, it shows a ...

The progression indicator on the mat-sidenav only displays halfway even when it shows 100 percent completed

I have encountered an issue with a simple mat progress bar in a mat side nav and content. When the value is set to 100, it should be completed, but it only fills halfway inside the content. Strangely, it works as expected in the side nav. https://i.sstat ...

Encountering a cyclic dependency issue

I am attempting to utilize the angular-jwt library in my Angular project, but I encountered a cyclic dependency error: Cannot instantiate cyclic dependency! InjectionToken_JWT_OPTIONS at NgModuleProviderAnalyzer.parse (compiler.js:19550) at NgModule ...

Insert a new item into an Observable within Ionic 4

My lecturer has been guiding me as a beginner in Ionic development. Currently, I am working on an Ionic 4 shopping application where users can add items to their wishlist. The item IDs are stored in the wishlist collection in Firebase Firestore. However, I ...