How to show options under select (Angular material 7)?

2.3k views Asked by At

How to show options under select (Angular material 7)? enter image description here

Something like default select:

enter image description here

2

There are 2 answers

0
Marshal On BEST ANSWER

The "correct" answer is to use the disableOptionCentering on your mat-select, but even this only prevents the placeholder from being covered and does not mimic the basic native select.

<mat-select placeholder="Favorite food" disableOptionCentering>

It is strongly frowned upon to do DOM manipulation of the native element in Angular, but this unfortunately, is the only way I have found to do stuff like this...

  • Hopefully someone will post a true "Angular" way to do this kind of stuff as I find myself manipulating the material library for these types of reasons.

You will need to wrap your options with a div wrapper and assign a templateRef #matOptionDiv so that you can use this in your component to grab the parent element(s) of your option drop down which is the CDK overlay.

<div #matOptionDiv>
   <mat-option *ngFor="let food of foods" [value]="food.value">
      {{food.viewValue}}
   </mat-option>
</div> 

Then use the click event on mat-form-field to trigger a method in your component to align the overlay

<mat-form-field (click)="positionDropDown()">

Then in your component use @ViewChild to grab the templateRef

import {Component, ViewChild} from '@angular/core';

@ViewChild('matOptionDiv') _matOptionDiv:any;

Then create your method to calculate new top value on the overlay and assign it... the setTimout is necessary to trigger change with the digest cycle.

positionDropDown(){
  let offsetY = 
  this._matOptionDiv.nativeElement.parentElement.parentElement.style.top

  setTimeout(()=>{this._matOptionDiv.nativeElement.parentElement.parentElement.style.top = parseInt(offsetY.slice(0, -2))+40+'px'},0)
  }

This is a very "hacky" solution and is not pretty, hopefully someone at some point will post an answer with a true "Angular" solution to this question.

  • Unfortunately there are calculations happening in the source of the mat-select to programmatically define the top of the overlay based on the viewable area via _calculateOverlayOffsetY... none of this is exposed in the API so I am not able to manipulate it "correctly" and I fear DOM manipulation may be the only way.

https://github.com/angular/material2/blob/6d7f41739207e469e626963d64e661401629902d/src/lib/select/select.ts#L1154

Here is Stackblitz for your review.

https://stackblitz.com/edit/angular-nafuur?embed=1&file=app/select-overview-example.ts

Revision

I did some more research on this and DOM manipulation is acceptable in angular as long as you are using Renderer2 as it interfaces with the DOM adapter and updates the DOM "appropriately"... making the DOM changes platform independent.

Please reference this youTube video for more information.

Can't Touch This! What not to do to the DOM by Max NgWizard


Stackblitz code update below

import {Component, ViewChild, ElementRef, Renderer2} from '@angular/core';

@ViewChild('matOptionDiv') _matOptionDiv:ElementRef;

constructor(private renderer: Renderer2) { }

 positionDropDown() {
    let offsetY = this._matOptionDiv.nativeElement.parentElement.parentElement.style.top;

    setTimeout(() => {
      // this._matOptionDiv.nativeElement.parentElement.parentElement.style.top = parseInt(offsetY.slice(0, -2))+40+'px'},0)
      this.renderer.setStyle(this.renderer.parentNode(this.renderer.parentNode(this._matOptionDiv.nativeElement)), 'top', parseInt(offsetY.slice(0, -2)) + 40 + 'px');
    });
  }
0
Glenn Jones On

The Docs where you got the screenshots from give a pretty comprehensive overview of how to include this component, just make sure you press the

<>

at the top right of the example for the code that created it. If it's something specific you're struggling with post the error(s) you're getting

https://material.angular.io/components/select/overview