Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MdSelect and MdAutocomplete slow initial render w/ large number of options #5113

Open
jelbourn opened this issue Jun 13, 2017 · 24 comments
Open
Labels
area: material/autocomplete area: material/select G This is is related to a Google internal issue P2 The issue is important to a large percentage of users, with a workaround perf This issue is related to performance

Comments

@jelbourn
Copy link
Member

For both MdSelect and MdAutocomplete, the initial render of the component (in the closed state) is very slow even though the panels are closed. We should ensure that any work related to the options is deferred until the panel is opened.

To reproduce this, simply modify the demos to render 500 md-select each with 500 options each (there is no problem if there are 500 selects with 1 option each).

@jelbourn jelbourn added the P2 The issue is important to a large percentage of users, with a workaround label Jun 13, 2017
@jelbourn jelbourn added the G This is is related to a Google internal issue label Oct 6, 2017
@jelbourn
Copy link
Member Author

jelbourn commented Oct 6, 2017

@crisbeto I think we should tackle this the same way we're dealing with tabs- to add an additional API where the options are in an ng-template so that they aren't eagerly instantiated. Thoughts?

@crisbeto
Copy link
Member

crisbeto commented Oct 6, 2017

Makes sense, I'll see what I can do.

@crisbeto
Copy link
Member

crisbeto commented Oct 7, 2017

@jelbourn I did some exploration into it. The problem with using an ng-template is that we count on the individual options to provide their text which we then use to display inside the trigger. Since they're not in place on load, it means that we won't be able to show the trigger text for preselected options until the first open. We could do something where the user provides the text, but it won't be very elegant.

@jelbourn
Copy link
Member Author

jelbourn commented Oct 7, 2017

We could add an extra API to the trigger for that case; the trade-off ends up being simplicity vs performance

@crisbeto
Copy link
Member

crisbeto commented Oct 7, 2017

We do have the mat-select-trigger component already which lets you override the trigger.

@jelbourn jelbourn added the perf This issue is related to performance label Oct 8, 2017
@jelbourn
Copy link
Member Author

jelbourn commented Oct 8, 2017

Thinking about it more, perhaps we need to go the route we took with the table here. Something like

<mat-select-trigger [panel]="panel">
  {{panel.selectedOption.name}}
</mat-select-trigger>

<mat-select-panel #panel [dataSource]="myOptions">
  <mat-option *matOptionDef="let option; when">{{option.name}}</mat-option>
</mat-select-panel>

It's a pretty dramatic departure from the current API- maybe we consider this for the next major release and instead say that lazily instantiated option-lists need to be explicitly given trigger text.

@crisbeto
Copy link
Member

crisbeto commented Oct 8, 2017

An alternative approach can be to hand over all rendering to Material. e.g. the user provides the data source and a function that determines what the output should look like:

<mat-select [options]="arrayOfOptions" [displayWith]="functionThatReturnsAString"></mat-select>

@jelbourn
Copy link
Member Author

jelbourn commented Oct 8, 2017

The issue there is that you lose the ability to custom-template the options. Even with the datasource approach you lose the ability to control how the options are expanded declaratively, but that might be a reasonable trade-off (we decided it was necessary for the table so it could have control over scrolling)

@ovoronin
Copy link

ovoronin commented Oct 12, 2017

I have such error for every item in mat-select

zone.js:1666 [Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event.

This #4221 (comment) helps, and the performance is much better (I have 900 items list)

@naveedahmed1
Copy link

Any update on this?

@debslord
Copy link

debslord commented Nov 7, 2017

I presume it will hopefully resolve #7749 and #4221 aswell.

I've tried the suggestion from #4221 with default passive events but I it hasn't helped the speed of loading my form which is taking around 20 seconds!

Any ideas on roughly when this might be resolved?

@timharris777
Copy link

I'm running into this same issue with Select and cannot find a workaround. If I have 100s of select options the view hangs on load (setting values in onInit). Anyone found a workaround?

@kylecordes
Copy link

@timharris777 I've worked around it by incrementally searching and loading a subset of the data. Code:

https://github.com/OasisDigital/angular-material-obs-autocomplete

demo:

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

What I like about this code: it works, yields a decent user experience, today. What I don't like about it: It doesn't "fix" the problem so much as avoided by implementing a different set of features, and it requires more work and understanding behind the scenes. See demo and demo code.

@swftvsn
Copy link
Contributor

swftvsn commented Aug 16, 2018

Was just hit by this. @jelbourn @crisbeto do you think cdk virtual-scroll should be used here now that it exists?

I don't know the specifics, but it sounds like it would work great!

@eamine84
Copy link

In IE / EDGE if I have a high number of mat-selects on a page, the opening of one of them is very slow. This happens if I have only one option too. Can anyone help me?

Angular 6.1.2
Angular material 6.4.5
Typescript 2.9.2

with material 5 this not happen !!!

@ghost
Copy link

ghost commented Aug 23, 2018

@swftvsn I've been working with some MdSelect and MdAutocomplete elements that have large lists (sometimes can reach 25.000 items), and they both become extremely slow (both for opening and searching through them).
For example, the ng-select lib has support for both auto-complete and virtual scrolling and on it, these lists behave quite well.
So, support for virtual-scroll on MdSelect and MdAutocomplete will be more than welcome.

@angular angular deleted a comment from vlrprbttst Jul 25, 2019
@garg10may
Copy link

As suggested by crisbeto this is giving me error.
<mat-select [options]="arrayOfOptions" [displayWith]="functionThatReturnsAString"></mat-select>

Can't bind to 'options' since it isn't a known property of 'mat-select'.

@mina-skunk
Copy link
Contributor

Lazy loading could have other benefits.

For example I'm facing when I have:

<mat-form-field>
  <mat-label>{{ type }}</mat-label>
  <mat-autocomplete #autocomplete>
    <mat-option *ngFor="let option of obsThatMakesHttpRequest | async">
      {{ option.DisplayName }}
    </mat-option>
  </mat-autocomplete>
  <input matInput [matAutocomplete]="autocomplete" />
</mat-form-field>

50 times, makes 50 request immediately, rather then one by one when you interact with them.

@mina-skunk
Copy link
Contributor

This is my work around

<mat-form-field>
  <mat-label>{{ type }}</mat-label>
  <mat-autocomplete #autocomplete>
    <ng-template [ngIf]="autocomplete.isOpen">
      <mat-option *ngFor="let option of obsThatMakesHttpRequest | async">
        {{ option.DisplayName }}
      </mat-option>
    </ng-template>
  </mat-autocomplete>
  <input matInput [matAutocomplete]="autocomplete" />
</mat-form-field>

@Harpush
Copy link

Harpush commented Aug 22, 2021

Any news on this?

@garg10may
Copy link

This is so slow in development, I switched to react along with material-UI for my new project. It offers highly advanced multi-select menus by default no third-party components are needed.

I won't recommend anybody using angular material, it's very slow in development. I got fooled by the 'Angular' keyword like its official UI for angular.

@nomankt
Copy link

nomankt commented Nov 15, 2021

+1

@mleibman
Copy link
Contributor

mleibman commented Jul 20, 2022

As @jelbourn mentioned before, fixing this in Angular Material would require a breaking API change, but for really bad cases with lots of <mat-option>s, I've been experimenting with a custom pipe that will let the currently-selected option(s) through until the select is either opened or the page has been idle long enough to load the rest.

import {
  Pipe,
  PipeTransform,
  OnDestroy,
  ChangeDetectorRef,
} from '@angular/core';
import { MatSelect } from '@angular/material/select';
import { Subscription } from 'rxjs';

/**
 * Initializes only the selected `<mat-option>`s to remove the up-front cost of
 * initializing and rendering off-DOM all of the select options, which can
 * number in thousands and make initial page rendering slow.
 */
@Pipe({ name: 'lazyOptions', pure: false })
export class LazyOptionsPipe implements PipeTransform, OnDestroy {
  private selectedOptionsOnly = true;
  private subscription: Subscription;

  constructor(
    private readonly select: MatSelect,
    private readonly cdr: ChangeDetectorRef
  ) {
    this.subscription = this.select.openedChange.subscribe(() => {
      this.selectedOptionsOnly = false;
    });

    // Preload after some time.
    requestIdleCallback(
      () => {
        this.selectedOptionsOnly = false;
        this.cdr.markForCheck();
      },
      { timeout: 1000 }
    );
  }

  transform<T>(values: T[]): T[] {
    if (!this.selectedOptionsOnly) {
      return values;
    }

    return values.filter((value) => {
      return this.select.compareWith(value, this.select.value);
    });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

To use, just specify it in your template:

<mat-form-field appearance="fill">
  <mat-label>Select an option</mat-label>
  <mat-select [(value)]="selected">
    <mat-option>None</mat-option>
    <mat-option *ngFor="let value of values | lazyOptions" [value]="value"
      >{{value}}</mat-option
    >
  </mat-select>
</mat-form-field>

@petarstf
Copy link

Bump.
Are there any updates on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: material/autocomplete area: material/select G This is is related to a Google internal issue P2 The issue is important to a large percentage of users, with a workaround perf This issue is related to performance
Projects
None yet
Development

No branches or pull requests