angular / components

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

virtual-scroll: integrate with relevant existing components #10122

Open mmalerba opened 6 years ago

mmalerba commented 6 years ago

Integrate virtual-scrolling as an optional add-on for relevant existing components, including:

Part of each integration should include adding docs examples of how to set it up

ThisIsIvan commented 5 years ago

Thanks for the response @rabelloo. I actually prefer the first method and already had something comparably implemented. I prefer it over fetching on request, because I feel it's a bad user experience to not see the full table length via the scroll bar, when you have a fixed amount of items.

That is of course not the case if you have an infinite long list. Thank you again!

piernik commented 5 years ago

@desdmit I'm trying to apply Your solution with CDK table (no material) but I cannot :/

https://stackblitz.com/edit/nahgrin-virtual-scroll-table-3tx3mt?file=src%2Fapp%2Ftable%2Ftable.component.html

You have there:

<ng-template let-row matRowDef cdkVirtualFor [matRowDefColumns]="displayedColumns" [cdkVirtualForOf]="rows">
      <mat-row></mat-row>
    </ng-template>

But how to translate it to plain cdk ?

<ng-template let-row cdkRowDef cdkVirtualFor [cdkRowDefColumns]="displayedColumns" [cdkVirtualForOf]="rows">
    <tr></tr>
</ng-template>

Is not working.

cedvdb commented 5 years ago

I vote for table semantics instead of divs. Display can always be changed to flex instead of table or row, so you can always get what you want visually and at least the html will be more readable.

doronsever commented 5 years ago

Can someone tell me how to calculate the _renderedContentOffset? I'm trying to implement our own table version with cdk-virtual-scroll but I cannot set our header component to be sticky. Then I found out that the CDK does a calculation of the content offset and if I set the header css top value to it's negative, it will fix it.

I looked at all the great example that was written here and tried to use the getOffsetToRenderedContentStart() function but it doesn't calculate the same value as _renderedContentOffset. If this value could have been at least not private one it would be good as well...

Also, @rabelloo could you please explain how you have access to the viewPort property? I don't see any declaration of it

NoureddineRmila commented 5 years ago

I Have Added Virtual scroll to my drag and drop and it causing problem see issue here #15457

rabelloo commented 5 years ago

@doronsever I'll assume you're asking about ExampleTableComponent since it's the only place viewport is not explicitly declared, in which case it is being inherited by the class it extends, CoreTable.

CoreTable is just a dirty way to avoid repeating code among all TableComponents, but alas component inheritance is not great as you can see. Essentially viewport comes from the Table's view, i.e. @ViewChild(CdkVirtualScrollViewport).

In regards to your _renderedContentOffset question, you could always access the private property if you want, even though there's no guarantee it will be available in future versions and I would not recommend it, e.g. (viewport as any)._renderedContentOffset or viewport['_renderedContentOffset'].

Regardless, I don't think using that private property would work either, gave it a try and couldn't make it work. If you do, please let me know how.

piernik commented 5 years ago

Can someone help with creating virtual scroll but for cdk-table ? I'd be very pleased :)

BTW. Do You think we can expect official support for that feature in version 8 ?

IlCallo commented 5 years ago

Based on previous statements from Angular team, they are fully focused on Ivy release and many Angular Material developers have been temporarly moved into the Angular Ivy team. They also said that there will probably be really few new features before Ivy becomes the default renderer (Angular 9 - fall 2019).

For what I understood: expect all major feature requests to be delayed until beginning of 2020 🤷‍♂️ And then there are more high priority issues than this, so maybe even later.

yantrab commented 5 years ago

@piernik check my npm package or check the source code here.

piernik commented 5 years ago

@yantrab I'm trying to create virtual scroll with cdk table. Here is my code: https://stackblitz.com/edit/cdk-virtual-table

Myu problems:

  1. I have 200 rows but it displays only 94 :/ Don't have clue why. Somehow this.viewport.setTotalContentSize is too small?

  2. When I scroll back to top few first rows are not rendered

  3. I don't know why You are using this line: const prevExtraData = start > (PAGESIZE / 2) ? (PAGESIZE / 2) : start;

yantrab commented 5 years ago

@piernik

  1. just remove [itemSize]="50" from cdk-virtual-scroll-viewpor.
  2. same as 1.
  3. to show 25 items before the current , to prevent blank section in fast scrolling. if start row smaller than 25, than render all rows from start.
omryoz commented 5 years ago

@shlomiassaf how can I use your code?

shlomiassaf commented 5 years ago

HI guys!

I've release NGrid as a library as well as open sourced the code.

https://github.com/shlomiassaf/ngrid

There is a documentation site and a simple starter to kick things quickly.

If anyone would like to contribute it will be much appreciated.

Let's face it, it's up to the community for this to work!

Documentation is the KEY to push this.

Thanks all

piernik commented 5 years ago

@shlomiassaf I have to admit that it's great! Making it bootstrap ready won't be a problem?

shlomiassaf commented 5 years ago

@piernik, what do you mean by bootstrap ready?

piernik commented 5 years ago

Theme: https://getbootstrap.com/

shlomiassaf commented 5 years ago

ohh, that bootstrap :)

Yes, of course, you can apply bootstrap style on it.

The basic grid does not have any material components in it (only CDK).

The idea is to have packages that add cell types like boolean, text, select, date, etc...
For each cell the package will include a view template and an edit template.

You can provide data to the templates (when defining columns) so it can be used for things like validation (min, max, etc...)

Of course it can also provide other things, like special headers (e.g. sorting in the header).

You might have a package adding a button at each header that exposes a menu to do things on the column (pin, hide, sort, filter by etc...), it's just a component.

Material components are added through @pebula/ngrid-material so adding this package gives you material like cells, the sorting via MatSort and more...

It's not complete yet, there is work to do, adding "edit" cells, context menu and header menus...

Lots of work on this grid, it has potential but I won't be able to push it without community help.

So to sum it up, just like @pebula/ngrid-material we can build @pebula/ngrid-bootstrap...

Thank you for the feedback 👍

erksmaas commented 5 years ago

@shlomiassaf, I am thoroughly impressed with what you've done! It's astounding what you've put together and how much is there and how well it all works in the first release!

mrandreev commented 5 years ago

@shlomiassaf great job! Thanks for sharing it with community.

But I would say its really huge library with a lot of customization, so its hard to figure out what is going on there and how to integrate virtual-scroll with material table. It will be great to have general solution how to achieve it with light material table.

Anyway at least we have alternative and source of code to play, so thanks :)

shlomiassaf commented 5 years ago

@mrandreev Thanks!

As I previously mentioned, it's really integrated into the grid and it requires some work to get it to work.

Because the material team did not fully integrate virtual scroll into the table (different components) there are a lot of features that does not work together.

For example, sticky rows & virtual scroll... You can read some of my previous comments in this thread with detailed info on things that can go wrong and some hints on how to get it done.

jelbourn commented 5 years ago

(I'm going through the highest voted issues today an commenting on their status)

We definitely plan on doing this, but the way most of the components are implemented today makes this a bit challenging. Components that need to know about their items (select, autocomplete, etc.) use @ContentChildren today. With virtual scrolling, though, that won't work. To make virtual-scrolling function, we'd have to do a larger rework on the components.

The data-table, though, uses a DataSource for its items, which makes this more straightforward. There still needs to be an abstraction layer to prevent people from getting the payload cost for virtual-scrolling (which is not tiny) for people using the table without that feature, but it will likely be the first thing that supports it. It's possible that we make some progress on this later in 2019 considering it's one of the higher priority feature requests on the backlog.

literalpie commented 5 years ago

I've also been looking into virtual scrolling in the table. Some of the POCs posted here have been really helpful, but sticky headers in the table were still causing problems. I found a solution, and thought I'd post it here so people can possibly use it.

The main idea is to use a "placeholder" row instead of the cdk virtual viewport's default behavior of using a transform. This allows the table to largely work the same as usual - including the sticky header.

here is the stackblitz

AshMcConnell commented 5 years ago

@piernik

  1. just remove [itemSize]="50" from cdk-virtual-scroll-viewpor.
  2. same as 1.
  3. to show 25 items before the current , to prevent blank section in fast scrolling. if start row smaller than 25, than render all rows from start.

I'm having similar problems, I tried removing itemSize, but I get: - Error: cdk-virtual-scroll-viewport requires the "itemSize" property to be set.. Am I missing something, or has the virtual viewport changed?

AshMcConnell commented 5 years ago

To answer my own question, you need to have the @angular/cdk-experimental installed and use the autosize directive on the cdk-virtual-scroll-viewport tag: -

e.g. <cdk-virtual-scroll-viewport autosize fxFlex="0 0 100">

IlCallo commented 5 years ago

(This comment was an answer to a now deleted comment asking for code)

Please read all the thread 🤨

HI guys!

I've release NGrid as a library as well as open sourced the code.

https://github.com/shlomiassaf/ngrid

There is a documentation site and a simple starter to kick things quickly.

If anyone would like to contribute it will be much appreciated.

Let's face it, it's up to the community for this to work!

Documentation is the KEY to push this.

Thanks all

nickwinger commented 5 years ago

actually i don't want to use NGrid, i just tried it. I want the workaround for pure material/cdk now trying out this version: https://stackblitz.com/edit/nahgrin-virtual-scroll-table-hampgc (i read the whole thread...)

simeyla commented 5 years ago

How do all these examples work when using async pipe data on the page.

For example I may have an observable defined in the model where I want to show how long ago an order was placed. Maybe this updates every minute like this.

timeSinceOrder$: Observable<string> = Timers.runEveryMinute$.pipe(switchMap(() => ... ), tap(() => console.log('timeSinceOrder$ has run');

The sample stackblitz above that I played with did not unsubscribe from the observable when it was scrolled out of view. So after scrolling all the way down and up I was seeing hundreds of log entries instead of just the number of rows I have in view.

For a final feature complete scrollable table I would think this would be a necessity - but there's no other mentions of async in this whole thread. How can I get that to work?

alexmacavei commented 5 years ago

On my previous project and ended up using http://swimlane.github.io/ngx-datatable/#virtual-paging. I know it's kind of annoying to have to rely on 3rd party libs for this, but it seemed to work pretty well until this ends up in Angular Material. At least for data tables :)

SaiSirishaS commented 5 years ago

@nahgrin I have tried your code and it works fine for the basic table structure. I have requirement, when i edit a table row it should open up a Matdialog. The matdialog doesn't work properly when scrolling after a certain number of rows in the table.

aalbericio commented 5 years ago

mat-select needs support for this asap :(

ahierro commented 5 years ago

I need this feature for mat-table, please!!

rahulyadav commented 5 years ago

@shlomiassaf : Great work on the ng-grid, works super cool... I was trying to implement the blocking scroll mode on cdk-virtual-scroll-viewport to prevent whitespace issues when scrolled too quickly. In my solution I've used the fixed scroll strategy and added wheel event listener on the cdk-virtual-scroll-viewport to prevent the default scroll behaviour. However, with this approach the scroll appear to be very sluggish and jumpy whereas your scroll implementation in ng-grid works seamlessly.

Can you give me some tips around how to get the block scrolling mode work smoothly?

ahierro commented 5 years ago

I ended up using primeng table component

Splaktar commented 5 years ago

I think that the UX of a select with virtual scroll is very questionable. If the user needs to pick from so many different options, then an autocomplete with virtual scroll would provide far better UX.

doronsever commented 5 years ago

There is a long waiting request to add a search inside the select list. When the material guys will implement it, the virtual scroll inside a select list is a very reasonable request

Splaktar commented 5 years ago

@doronsever That's not currently a feature of the Material Design guidelines for menus, which is where the select menu (popup panel) behavior is defined.

The closest that I could find was the Editable Exposed Dropdown Menu example. However, this is designed to allow entering a value that isn't in the options set. It doesn't describe any filtering behavior (I think that's still TBD).

camillewall commented 5 years ago

I have tried both @rabelloo and @lujian98 as examples to implement virtual scrolling using the material CDK. But, they both have a problem I cannot figure out and it is around using a checkbox to select rows. I added a select checkbox to @lujian98 example. When the list first gets rendered everything is great I can click on the checkbox and the check appears immediately. Once scrolling starts and you go past the rows that are initially rendered then checking no longer happens when clicked, but when focus is lost. Any help would be appreciated.

elimb commented 5 years ago

@camillewall I had a similar issue using literalpie's initial solution. I ended up running setTimeout(()=>this.appRef.tick()) on row clicks which solved my checkbox issue. I would think that there must be a better solution though.

mike-lipin commented 5 years ago

@camillewall I had a similar issue using literalpie's initial solution. I ended up running setTimeout(()=>this.appRef.tick()) on row clicks which solved my checkbox issue. I would think that there must be a better solution though.

@camillewall there is another workaround. you may inject ChangeDetectorRef into the directive and force change detection on each click like this

constructor(private ref: ChangeDetectorRef) {}

@HostListener('click')
queueChangeDetection() {
    this.ref.markForCheck();
}
camillewall commented 5 years ago

Thank you @elimb and @mike-lipin for your help. My checkboxes are showing they are clicked without any delay.

divyanshumehta commented 5 years ago

Damm so many people worked on their own versions of the virtual scrolling version of mat-table, I thought angular team would have integrated the virtual scroll by now. Please lets get this feature soon

ghost commented 4 years ago

Hey everyone,

For those in need of a virtually scrolling tree, I put together a stackblitz demonstrating how I managed to work around the fact that cdk-tree does not yet support virtual scrolling out of the box

https://stackblitz.com/edit/angular-b5nkkd?file=src/app/app.component.html (it shows a normal flat tree and a virtually scrolling one side by side) Selling point is that if you already have a cdk flat tree working using the proper data source and tree control, this requires very little modification to get a nicely working virtual scroll without any brittle hacks.

And here's a stack overflow response I wrote with more detail for someone that was having this same exact problem: https://stackoverflow.com/questions/52606511/angular-material-cdk-tree-component-with-virtual-scroll/58846134#58846134

kekel87 commented 4 years ago

Hi, new for this issue?

I currently have a mat-table with custom virtual scroll, I try all the proposed solutions here, but none works correctly with a mat-tooltip on an element of the table (after scroll).

maranmaran commented 4 years ago

I have a problem with this in a mat-menu. I have time though, does anyone have a workaround for mat-menu in the meantime perhaps?

ARUS911 commented 4 years ago

almost 2 years ... (

blogcraft commented 4 years ago

Nothing yet?

nate-knight commented 4 years ago

Does anybody have a recommendation on how to get drag/drop to work with a virtually-scrolled CDK table? I have implemented a virtual scroll solution based off of the wonderful examples provided by @shlomiassaf @nahgrin and @rabelloo . The issue I face is that when dragging an item from the current "view" of the table, and then autoscrolling the table to a point where the table displays the next subset of data, the dragged item is lost and the table just continues to scroll. This seems to happen because these solutions directly replace the table's dataSource with a new subset of the total data. And one a new datasource on the table is set, the dragged item is lost because it was attached to the previous dataSource. With the CDK's *ngVirtualFor directive on lists of elements (not tables), the datasource is not replaced, so the user can drag an item from one subset of data to the next subset. I'm not sure of a workaround for the cdk table use-case. Any insight and help is welcome!

attilacsanyi commented 4 years ago

Dear @nate-knight can you point to the wonderful solution of mat table with virtual scroll please based on @shlomiassaf @nahgrin and @rabelloo. I have this example so far. Appreciate your help.

JKremsner commented 4 years ago

Thanks @attilacsanyi for the example but sorting still doesn't work as expected.

TomaszKasowicz commented 4 years ago

Hi All.

I recently started investigating on How to implement Virtual Scroll for Table with pages being dynamically loaded on scroll. After reading through this whole thread and looking into examples I decided to use as less code as possible.

So based on example by @rabelloo and instructions on how to use data source with paging in scrolling (https://material.angular.io/cdk/scrolling/overview) I created Data Source instance which

  1. Uses MatTableDataSource to have all the data sorted (or filtered if needed)
  2. Acts as CdkVirtualForOf for CdkVirtualScrollViewport.attach() so view port can calculate data size
  3. Subscribes to range changes to trigger additional data fetches and data updates

The example code is available here: https://stackblitz.com/edit/angular-qrbbwr

(Note: this one is without sticky header... I'll try to work on it later)