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.
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.
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.
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.
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.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...
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.Then use the click event on
mat-form-field
to trigger a method in your component to align the overlayThen in your component use
@ViewChild
to grab the templateRefThen 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.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.
_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