What is the way to use the MAT_AUTOCOMPLETE_DEFAULT_OPTIONS injection token, or the const AUTOCOMPLETE_OPTION_HEIGHT to customize mat-autocomplete. These constants, among ot
It's quite weird, why such a needed option like the height of item (option) isn't defined as input.
Because without changing of AUTOCOMPLETE_OPTION_HEIGHT
we will get a bug (https://github.com/angular/components/issues/18030)
Here is a possible solution:
Step 1. Change style.It's the easiest moment. We can just change the global style. Let's use 24px instead 48px
mat-option.mat-option{
position: relative;
height: 24px!important;
line-height: 24px!important;
max-height: 24px!important;
}
Step 2. Overwrite original _scrollToOption
method of MatAutocompleteTrigger
The pain is located here: https://github.com/angular/components/blob/49a1324acc05cec1c5ff28d729abfe590f6772dd/src/material/autocomplete/autocomplete-trigger.ts line 498, method _scrollToOption
.
This method takes two hardcoded constants (AUTOCOMPLETE_OPTION_HEIGHT
, AUTOCOMPLETE_PANEL_HEIGHT
) and uses it to calculate new scroll position. Sure, if you have not 48px, but less or more - it will work incorrectly.
So, we have to overwrite this method.
The most elegant way to do it - using Directive
(keep in mind, we can get access with @ViewChild()
to MatAutocompleteTrigger
and change it in the scope of a parent component, but it's not a reusable solution).
import { Directive } from '@angular/core';
import { Host, Self, Optional, Input, OnInit } from '@angular/core';
import { MatAutocompleteTrigger, AUTOCOMPLETE_OPTION_HEIGHT, AUTOCOMPLETE_PANEL_HEIGHT } from '@angular/material';
import {
_countGroupLabelsBeforeOption,
_getOptionScrollPosition
} from '@angular/material/core';
@Directive({
selector: '[matAutocompleteTriggerAccessor]',
})
export class DirectiveAccessor implements OnInit {
@Input() optionHeight: number = AUTOCOMPLETE_OPTION_HEIGHT;
@Input() panelHeight: number = AUTOCOMPLETE_PANEL_HEIGHT;
constructor(
@Host() @Self() @Optional() public _refTrigger: MatAutocompleteTrigger
) { }
public ngOnInit() {
if (this._refTrigger === undefined || this._refTrigger === null) {
return;
}
this._refTrigger['_scrollToOption'] = this._scrollToOption.bind(this._refTrigger, this.optionHeight, this.panelHeight);
}
private _scrollToOption(
this: MatAutocompleteTrigger,
optionHeight: number,
panelHeight: number,
): void {
const index = this.autocomplete._keyManager.activeItemIndex || 0;
const labelCount = _countGroupLabelsBeforeOption(
index,
this.autocomplete.options,
this.autocomplete.optionGroups
);
if (index === 0 && labelCount === 1) {
this.autocomplete._setScrollTop(0);
} else {
const newScrollPosition = _getOptionScrollPosition(
index + labelCount,
optionHeight,
this.autocomplete._getScrollTop(),
panelHeight
);
this.autocomplete._setScrollTop(newScrollPosition);
}
}
}
_scrollToOption
method. Only one thing we do - avoid using constants: AUTOCOMPLETE_OPTION_HEIGHT
, AUTOCOMPLETE_PANEL_HEIGHT
optionHeight
and panelHeight
AUTOCOMPLETE_OPTION_HEIGHT
, AUTOCOMPLETE_PANEL_HEIGHT
Now we can modify our template and add a new directive and addition inputs.
Note. Our directive matAutocompleteTriggerAccessor
and input optionHeight
should be attached to , but not to
.
And that's all. Now all works as it should.
Here is a full solution: https://stackblitz.com/edit/angular-cn4ox8