How to use Angular Material MAT_AUTOCOMPLETE_DEFAULT_OPTIONS injection token

后端 未结 2 1869
情话喂你
情话喂你 2021-01-18 07:03

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

2条回答
  •  粉色の甜心
    2021-01-18 07:31

    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).

    Step 2.1. Create directive
    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);
          }
      }
    }
    
    • So, we use "original" code of _scrollToOption method. Only one thing we do - avoid using constants: AUTOCOMPLETE_OPTION_HEIGHT, AUTOCOMPLETE_PANEL_HEIGHT
    • instead these constants we are adding two inputs optionHeight and panelHeight
    • as defaults values for new inputs, we are using values of AUTOCOMPLETE_OPTION_HEIGHT, AUTOCOMPLETE_PANEL_HEIGHT
    Step 2.2. Add directive and addition inputs

    Now we can modify our template and add a new directive and addition inputs.

    {{option}}

    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

提交回复
热议问题