angular / components

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

[Accordion] Rendering many expansion panels is slow #8287

Open ztgluis opened 7 years ago

ztgluis commented 7 years ago

Bug Report

Hello, wanted to post here an issue I haven't seen posted already.

Trying to use mat-accordion with expansion panels to display large amounts of data and noticed a decrease on performance and slow animation and rendering time.

You might suggest that accordions are not best suited to display large amounts of data or that I should paginate, but for my specific use case I do need to display those large amounts of data and the accordion look and feel is exactly what I'm looking for.

Here is a Stackblitz demonstrating the slow performance, uncommenting lines 14 and 17 of the app.component.ts file will increasingly affect performance (and maybe crash your browser?):

https://stackblitz.com/edit/angular-bg9puu?file=app%2Fapp.component.ts

Using latest Angular 5.0.0 and Material 5.0.0-rc0 for the stackblitz but having the same issue in Angular 4.4.6 and Material 2.0.0-beta.12

willshowell commented 7 years ago

Maybe https://github.com/angular/material2/pull/8243 will help

oktav777 commented 7 years ago

In this particular case you have generated ~4850 accordion elements. I opened your example in a separate tab (https://angular-bg9puu.stackblitz.io/) in latest Chrome. The scrolling works smooth as butter. Opening an accordion is a bit clunky, i'm surprised that it even works, and the lag is not as big as I thought. Don't know if a native element in some native app could perform better with ~4800 elements. I know, you wrote about this, but I think you are doing something wrong in terms of UI, if you have to display your data like this.

If you still want to display data in this way, try a virtual scroll, maybe it can help.

ztgluis commented 7 years ago

@oktav777, I know these many elements are not a great idea, but you know, sometimes you get requirements like that.

Regardless of that specific use case, I believe the problem is actually not with the accordion/expansion-panels but with the animations, I am also noticing some animation issues when there's too many elements in the DOM (plain old html elements like divs and spans) and only a handful of expansion panels or material components.

Here's another stackblitz with a lot of plain and unstyled spans and only 3 expansion-panels (and also threw in there 3 mat-selects because same issue is there) you can clearly see animations for both the accordion and select get sluggish even if there's only 3 of each.

https://stackblitz.com/edit/angular-vsjp54?file=app%2Fapp.component.ts

Edit: To see the slow rendering uncomment lines 14, 17 and 18 from app.component.ts on the stackblitz, it can get very slow to load and might crash your browser.

josephperrott commented 7 years ago

We will continue to look into seeing if it can be optimized at all, however this is unfortunately expected.

Because the the animation causes a change in the offsetHeight of the <mat-expansion-panel> instance, there is an amount of layout recalc and repainting that must occur. You can see that this is improve a bit by both using the displayMode="flat" on the mat-accordion or to use NoopAnimationsModule to prevent the animations entirely. This is because the recalc and repaint occurs less often in both cases.

DinoSourcesRex commented 6 years ago

Just to chime in here: I am currently utilising auto-complete with a list which drives my expansion panel, which is lazy-loading up-to 571 elements - anything above 350 gives me a noticable lag in the redraw, what is the suggested method for offsetting / staggering / hiding this lag?

I'm currently on material 5.2.0.

mackelito commented 6 years ago

By using trackBy and OnPush you will gain some performance but still there is more work needed go get GOOD performance.. using hideToggle="true" will also have some improvements..

https://stackblitz.com/edit/angular-mmp39g?file=app%2Fapp.component.html

I would also try out a virtual scroll in this case

DinoSourcesRex commented 6 years ago

@mackelito after seeing that example I've a feeling something is wrong with my implementation so I'll root around and see what the differences are. Thanks!

Also if you have any virtual list recommendations please reachout, I'm eagerly following the feature request for a material virtual scroll.

mackelito commented 6 years ago

@DinoSourcesRex I'm waiting for the material version as well.. have not really found a good one so far.. I just hope the material one will "support" flex-layout's row wrapped items ;)

SaturnTeam commented 6 years ago

I have the same issue on material 6.0

supersirk commented 6 years ago

leave it here if it helps: I had the same lagging issue: i solved it with one css line by fixing the height of the container div around the accordion.

@ztgluis : i got your example working like a charm just wrapping mat-accordion with <div style="position: absolute; width: 100vw; height: 100vh; top: 0; left: 0;"> and it became all smooth

pshurygin commented 6 years ago

I have noticed that when you toggle an expansion panel the entire page is being repainted every time(using chrome paint flashing). I have migrated to angular material from angular-ui-bootstrap, where i had the exact same accordion implemented with uib-accordion and it was not the case with it. Only the expansion panel was repainted, which also resulted in a much better animation performance.

Is there some kind of optimization/page layout you could implement to negate this issue(which were not already mentioned)? It was really unexpected for me to see degraded performance compared to uib-accordion(and angular.js) as I thought moving to angular 2+ would increase performance not cripple it.

benelliott commented 6 years ago

@pshurygin It's not possible to implement the accordion behaviour without some amount of repainting. The extent to which your app is repainted when you expand/collapse the accordion depends on the specific layout of your app. For example, try setting position: absolute on the expansion panels in this demo, taken from the docs:

https://lpqkamaqobq.angular.stackblitz.io/

You will notice that doing so prevents the expansion from repainting the entire page as it has been taken out of the document flow.

UrbanNuke commented 5 years ago

@mackelito Thanks! hideToggle="true" it's work for me. I also not used ChangeDetectionStrategy.OnPush and trackBy and work it :)