angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.34k stars 6.74k forks source link

(Feature request) Custom template for autocomplete/select options #7477

Open faelmorais opened 7 years ago

faelmorais commented 7 years ago

Bug, feature request, or proposal:

Feature request

What is the expected behavior?

Possibility to use autocomplete or select with custom templates to show styled options, like on Angular Material for AngularJS autocomplete here.

Example:

captura de tela 2017-10-02 as 14 04 42

What is the current behavior?

All options are shown using a single line option template.

What are the steps to reproduce?

It can be seen on the docs here.

What is the use-case or motivation for changing an existing behavior?

Allowing the customization of the options for the autocomplete/select can help creating a better user experience.

kylecordes commented 6 years ago

We found that we can use a custom template. We managed to put in a mat-table, and it all worked compatibly with the auto complete by putting the actual data payload in a . well, almost. It took a bit of overwriting CSS to make row highlighting work.

AsafAgranat commented 6 years ago

@kylecordes - I found the same thing, but indeed the highlighting of the rows is off, once the height of each option element is altered. In my case, the option height was larger (to include several lines), but then the highlighted (focused) option goes out of it's parent container - I assume because the parent container is calculated as #items x itemHeight. Can you please share you CSS workaround to this issue?

kylecordes commented 6 years ago

@AsafAgranat I'll take a look at how we solved this problem in CSS, and see if there is a straightforward way to make the published demo do the same thing.

kylecordes commented 6 years ago

@AsafAgranat I finally got back to publishing my example of mat-table inside a auto complete drop-down. unfortunately I haven't hit the situation you describe after all, I have not had a need to change the height of the rows, and therefore the highlighting "just works". You can see it in action here:

https://oasisdigital.github.io/angular-material-obs-autocomplete/multi

The code for this bit is here:

https://github.com/OasisDigital/angular-material-obs-autocomplete/tree/master/src/app/select-company-mat-table

If you point out a small change there that would reproduce the problem though, I will try to help. It seems to me that a mat-table is as example of composing multiple Material components together to achieve the sort of "custom template" that this issue is a request for.

manfromanotherland commented 5 years ago

Are there any plans to implement this?

alialtun14 commented 5 years ago

custom template example for material autocomplete https://stackblitz.com/edit/angular-roxiwd?file=app%2Fautocomplete-overview-example.html

AsafAgranat commented 5 years ago

@alialtun14, your example does not help for the issue here. Your example uses the default option height from Material. The issue here refers to an option template that has a height different than the default height.

orelchykova commented 1 year ago

I've faced the issue of implementation custom option. The only solution now is override styles like:

.mat-select-panel {
  min-width: calc(100% + 21px) !important;
  border: 1px solid $light-grey;
  border-radius: 10px !important;
  box-shadow: none !important;
  max-height: 215px;

    .mat-option {
      padding: 9px 20px;
    }
  }

But next issue that appears is using keyboard navigation, it became broken. The reason is that scroll method in angular mat-select uses constant value for option height. _scrollActiveOptionIntoView uses this._getItemHeight() which is based on em constant height:

 private _getItemHeight(): number {
    return this._triggerFontSize * SELECT_ITEM_HEIGHT_EM;
  }

also _scrollActiveOptionIntoView uses SELECT_PANEL_MAX_HEIGHT which is 256px (.mat-select-panel { max-height: 256px;})

line 1050 - https://github.com/angular/components/blob/49a1324acc05cec1c5ff28d729abfe590f6772dd/src/material/select/select.ts

To solve that I created directive that will override private method _scrollActiveOptionIntoView:

const SELECT_PANEL_MAX_HEIGHT = 215;

@Directive({
  selector: '[matSelectAccessor]',
})
export class MatSelectAccessor implements OnInit {
  constructor(@Host() @Self() @Optional() public _refSelect: MatSelect) {}

  public ngOnInit() {
    if (!this._refSelect) {
      return;
    }
    this._refSelect['_scrollOptionIntoView'] = this._scrollOptionIntoView.bind(this);
  }

  private _scrollOptionIntoView(index: number): void {
    const labelCount = _countGroupLabelsBeforeOption(index, this._refSelect.options, this._refSelect.optionGroups);
    // Get option height in case of option custom styles
    const optionRect = this._refSelect.options.first._getHostElement().getBoundingClientRect();
    const itemHeight = optionRect.height;
    if (index === 0 && labelCount === 1) {
      this._refSelect.panel.nativeElement.scrollTop = 0;
    } else {
      this._refSelect.panel.nativeElement.scrollTop = _getOptionScrollPosition(
        (index + labelCount) * itemHeight,
        itemHeight,
        this._refSelect.panel.nativeElement.scrollTop,
        SELECT_PANEL_MAX_HEIGHT,
      );
    }
  }
}

Here I've override _scrollOptionIntoView because I changed select-panel height also and updated both values. But you also can override only _getItemHeight by this._refSelect.options.first._getHostElement().getBoundingClientRect(); but is used for calculations for several methods so need to check side effects.

Using of directive:

   <mat-select
        matSelectAccessor
        panelClass="payment-form-select"
        formControlName="cardHolderCountryCode"
        (selectionChange)="onChangeCountry($event)"
        [disableOptionCentering]="true"
      >
        <mat-option *ngFor="let country of countryInfo" [value]="country.code"> {{ country.name }} </mat-option>
   </mat-select>