bug/feature request
panel position should be recalculated relatively to current md-option height
md-option height is hardcoded, so panel position is same regardless of current md-option height which causes misalignment of the select panel
current height is way too big for some UI designs, there should be way to customize it
any news here?
@crisbeto could you take a look, please
This would be great function for my use-case
This would be great function for any, who would like to use md-option
components 鈽濓笍
Any news or known workaround ?
Nope, still waiting for implementation : /
No workaround is possible?
Nope, still waiting : /
Possible work-around:
In your component get a reference to the MatSelect with bigger options, and override it's _getItemHeight
with your own height calculation.
@ViewChild('xlFood')
private xlFood: MatSelect;
ngAfterViewInit() {
(<any> this.xlFood)._getItemHeight = () => this.xlFood._triggerFontSize * 5; // default is 3em
}
Example: https://stackblitz.com/edit/angular-material2-issue-swsdrn?file=app%2Fapp.component.ts
Here is my workaround:
// the input element with the matAutocomplete attached to it (<input [matAutocomplete]="autoCompleteComponent">)
@ViewChild('autoCompleteInput', {read: MatAutocompleteTrigger}) matAutocompleteTrigger: MatAutocompleteTrigger;
// the mat auto-complete component itself (<mat-autocomplete #autoCompleteComponent="matAutocomplete">)
@ViewChild('autoCompleteComponent', {read: MatAutocomplete}) autoCompleteComponent: MatAutocomplete;
this.matAutocompleteTrigger['_scrollToOption'] = () => {
const index: number = this.autoCompleteComponent['_keyManager'].activeItemIndex || 0;
const labelCount = _countGroupLabelsBeforeOption(index, this.autoCompleteComponent.options, this.autoCompleteComponent.optionGroups);
const newScrollPosition = _getOptionScrollPosition(index + labelCount, AUTOCOMPLETE_OPTION_HEIGHT, this.autoCompleteComponent._getScrollTop(), AUTOCOMPLETE_PANEL_HEIGHT);
this.autoCompleteComponent._setScrollTop(newScrollPosition);
};
@danmana Thanks for this work around. It works really well. Even though for how long, since _getItemHeight()
supposed to be private.
But by this workaround you can see, that it would not be so hard to make the itemHeight customisable. So I hope this can be somehow implemented in a future version.
Would be great if the AUTOCOMPLETE_OPTION_HEIGHT was an injection token that could be set. Or, completely remove the need for this, by using Element.scrollIntoView()
on the option element.
@pwnball , can you kindly expand on your workaround? Any chance you can setup a quick Stackblitz? I'm not quite sure when you are calling the this.matAutocompleteTrigger['_scrollToOption'].
Will be appreciated. Tnx
@AsafAgranat I found that the <input>
tag needs a #variable
that you use in the "@ViewChild"
Example: //in the html <input #variable [matAutocomplete]="autoCompleteComponent">
//in the ts @ViewChild('variable', {read: MatAutocompleteTrigger}) matAutocompleteTrigger: MatAutocompleteTrigger;
I'm just using your hack @pwnball but instead of overriding the const values it will work just using:
element.scrollIntoView({block:'end'});
or
element.scrollIntoView({block:'start'});
depending on the direction...
This is my complete fix with no hardcoded height of neither panel nor option:
ngAfterViewInit(): void {
this.matAutocompleteTrigger['_scrollToOption'] = () => {
const activeMatOption: MatOption | null = this.activeMatOption;
if (null !== activeMatOption) {
const optionElement = activeMatOption._getHostElement();
const optionBox = optionElement.getBoundingClientRect();
const panelBox = this.matAutocomplete.panel.nativeElement.getBoundingClientRect();
if (optionBox.top < panelBox.top) {
optionElement.scrollIntoView({ block: 'start' });
} else if (optionBox.bottom > panelBox.bottom) {
optionElement.scrollIntoView({ block: 'end' });
}
}
};
}
@glebmachine @jcudzich I did create a pull request but guess something went wrong...
Here is my workaround:
// the input element with the matAutocomplete attached to it (<input [matAutocomplete]="autoCompleteComponent">) @ViewChild('autoCompleteInput', {read: MatAutocompleteTrigger}) matAutocompleteTrigger: MatAutocompleteTrigger; // the mat auto-complete component itself (<mat-autocomplete #autoCompleteComponent="matAutocomplete">) @ViewChild('autoCompleteComponent', {read: MatAutocomplete}) autoCompleteComponent: MatAutocomplete; this.matAutocompleteTrigger['_scrollToOption'] = () => { const index: number = this.autoCompleteComponent['_keyManager'].activeItemIndex || 0; const labelCount = _countGroupLabelsBeforeOption(index, this.autoCompleteComponent.options, this.autoCompleteComponent.optionGroups); const newScrollPosition = _getOptionScrollPosition(index + labelCount, AUTOCOMPLETE_OPTION_HEIGHT, this.autoCompleteComponent._getScrollTop(), AUTOCOMPLETE_PANEL_HEIGHT); this.autoCompleteComponent._setScrollTop(newScrollPosition); };
@pwnball @AsafAgranat this.matAutocompleteTrigger['_scrollToOption'].
Where to call this, I tried inside ngonint andaftervew init shows undefined
Hi guys,
is there a way to adapt this autocomplete-scenario to mat-select?
I already tried if there is something similar like this.matselect['_scrollToOption'] but it seems that there is no such event.
Any ideas?
Hi a solution for reuse the @danmana solution on all components
create a directive:
import { Directive } from '@angular/core';
import { MatSelect } from '@angular/material';
import {
_countGroupLabelsBeforeOption,
_getOptionScrollPosition
} from '@angular/material/core';
@Directive({
selector: '[appMatOptionHeight]'
})
export class MatOptionHeightDirective {
constructor(
public matSelect: MatSelect
) {
(<any> this.matSelect)._getItemHeight = () => this.matSelect._triggerFontSize * 1.5;
}
}
and add to html <mat-select appMatOptionHeight>
In Angular 9.1.7 _getItemHeight is a private property of MatSelect. so unable to access outside.
@danmana @YanDuc solution work up to angular version 8
Any update on this issue ?
@Shrinivassab
Late response, but you're not intended to call that function. Its an internal function in the angular component that contains a flaw. Basically I rewrote the function to function with the value I wanted, rather than their hardcoded value.
@gowthaman-i2i the solutions still work in Angular 9.1.11
Note that the solutions shown here do not set the option height, you have to do that on your own, either via css or js.
I've extended @YanDuc directive (nice idea) to also set the option height (and accept a configurable height in em)
You can see it here https://stackblitz.com/edit/angular-ivy-9wfzdg?file=src%2Fapp%2Fmat-option-height.directive.ts
@gowthaman-i2i the solutions still work in Angular 9.1.11
Note that the solutions shown here do not set the option height, you have to do that on your own, either via css or js.
@danmana thanks for your reply. I have tried to get "_getItemHeight" property but it's masked as Private in angular/material select file so unable to access outside
tried example here https://stackblitz.com/edit/angular-yv2zvm
@gowthaman-i2i Yes, the field is private, but you can access it when casting as <any>
. I don't see any errors running the code.
I noticed in your example that you forgot to add the directive to the NgModule declarations, so it was not getting picked up by Angular at all. That's why it wasn't working.
Here is a fork from your example https://stackblitz.com/edit/angular-yv2zvm-8vvase
Changes I did:
Most helpful comment
@crisbeto could you take a look, please