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

virtual-scroll: support multiple items per row #10114

Open
mmalerba opened this issue Feb 23, 2018 · 42 comments · May be fixed by #29453
Open

virtual-scroll: support multiple items per row #10114

mmalerba opened this issue Feb 23, 2018 · 42 comments · May be fixed by #29453
Labels
area: cdk/scrolling feature This issue represents a new feature or feature request rather than a bug or bug fix P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent

Comments

@mmalerba
Copy link
Contributor

Allow the user to specify the number of items per row in the fixed size scrolling strategy

@mmalerba mmalerba self-assigned this Feb 23, 2018
@mmalerba mmalerba added the feature This issue represents a new feature or feature request rather than a bug or bug fix label Feb 23, 2018
@filipemendes1994
Copy link

@mmalerba any news about this?

@mmalerba
Copy link
Contributor Author

Most of our effort is focused on integrating with MDC right now. When I have time to do more work on virtual scroll, finishing up the missing parts of the autosize strategy will be my top priority , so this one might have to wait a while

@bebeto84
Copy link

Hi @mmalerba any updates on this? Is there at least prevision if this feature will be on the pipeline?

Thanks!

@pl4yradam
Copy link

+1 this would be amazing

@SvenBudak
Copy link

Any news about this? it seems it's currently not possible to build a real world contentful app with angular. :/

@SurenAvagyanG
Copy link

please give any update of possible

@tdhulster
Copy link

In the meantime you can use display:grid by overriding the css

::ng-deep{
  .cdk-virtual-scroll-content-wrapper {
    display: grid;
    grid-template-columns: 50% 50%;
  }
}

@hdadr
Copy link

hdadr commented Feb 22, 2020

Any update on this?

@daniel-halldorsson
Copy link

I got issues trying to use the display: grid technique above, it looked like it would work but then found it would randomly jump back to previously scrolled locations and was unusable. Official support for multi column would be amazing, +1

@SvenBudak
Copy link

We solve it with modulo operator...

@mmalerba
Copy link
Contributor Author

The team does plan to work on this (and other virtual scroll features), but it won't happen this quarter. Our current areas of focus are component harnesses, integration with MDC Web, and the date range picker

@daniel-halldorsson
Copy link

daniel-halldorsson commented Feb 29, 2020

Great news, in the mean time, i solved it by chunking my data and wrapping it in a row component with a fixed height. I used BreakpointObserver from cdk layout to determine the amount of chunking required (ie. 1 thumbnail per row on mobile, up to 8 on desktop, depending on width)

@daniel-halldorsson
Copy link

We solve it with modulo operator...

can you give some more information on that?

@mmalerba mmalerba added the needs triage This issue needs to be triaged by the team label May 20, 2020
@crisbeto crisbeto added area: cdk/scrolling and removed needs triage This issue needs to be triaged by the team labels May 25, 2020
@crisbeto crisbeto added the P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent label May 25, 2020
@Albertbol
Copy link

Up

@lincolnthree
Copy link

https://github.com/rintoj/ngx-virtual-scroller Has an implementation of multiple items per row, if anyone wants to look at how it's done (or get something working today.)

@enesien
Copy link

enesien commented Oct 6, 2020

I was able to "chunk" my array into rows with 4 items each. Then the cdkVirtualFor becomes your rows, your [itemSize] becomes the height of the row, and you loop over the "columns" inside the virtualfor.

      let i: number, j: number, temparray: Card[][] = [], chunk = 4;
      for (i = 0, j = r.length; i < j; i += chunk) {
        temparray.push(r.slice(i, i + chunk));
      }
      this.all = temparray;
        <cdk-virtual-scroll-viewport class="h-100" [itemSize]="130">
            <div class="row no-gutters" *cdkVirtualFor="let row of all">
                <div class="col-3" *ngFor="let card of row">
                    <card-image [card]="card"></card-image>
                </div>
            </div>
        </cdk-virtual-scroll-viewport>

@michele-bergia
Copy link

Is there any workaround to have multiple items per row when having *cdkVirtualFor working with DataSource<T>?

@joharzmn
Copy link

joharzmn commented Jan 5, 2021

Any Update on this?

@timsar2
Copy link

timsar2 commented Jan 27, 2021

?

@tayambamwanza
Copy link

I was able to "chunk" my array into rows with 4 items each. Then the cdkVirtualFor becomes your rows, your [itemSize] becomes the height of the row, and you loop over the "columns" inside the virtualfor.

      let i: number, j: number, temparray: Card[][] = [], chunk = 4;
      for (i = 0, j = r.length; i < j; i += chunk) {
        temparray.push(r.slice(i, i + chunk));
      }
      this.all = temparray;
        <cdk-virtual-scroll-viewport class="h-100" [itemSize]="130">
            <div class="row no-gutters" *cdkVirtualFor="let row of all">
                <div class="col-3" *ngFor="let card of row">
                    <card-image [card]="card"></card-image>
                </div>
            </div>
        </cdk-virtual-scroll-viewport>

@enesien This is a good alternative for the time being, thanks for posting this.

@Baluditor
Copy link

I was able to "chunk" my array into rows with 4 items each. Then the cdkVirtualFor becomes your rows, your [itemSize] becomes the height of the row, and you loop over the "columns" inside the virtualfor.

      let i: number, j: number, temparray: Card[][] = [], chunk = 4;
      for (i = 0, j = r.length; i < j; i += chunk) {
        temparray.push(r.slice(i, i + chunk));
      }
      this.all = temparray;
        <cdk-virtual-scroll-viewport class="h-100" [itemSize]="130">
            <div class="row no-gutters" *cdkVirtualFor="let row of all">
                <div class="col-3" *ngFor="let card of row">
                    <card-image [card]="card"></card-image>
                </div>
            </div>
        </cdk-virtual-scroll-viewport>

Thank you for this.

I had to add inline-block to <div class="col-3" *ngFor="let card of row"> get it work.

@nerd-cs
Copy link

nerd-cs commented Mar 24, 2021

In the meantime you can use display:grid by overriding the css

::ng-deep{
  .cdk-virtual-scroll-content-wrapper {
    display: grid;
    grid-template-columns: 50% 50%;
  }
}

@tdhulster, @mmalerba
This is a good solution, I think

Particularly, we should set itemSize
<cdk-virtual-scroll-viewport [itemSize]="itemSize">

If you want 2 columns per row then itemSize = half value of size (in pixels)
For the responsiveness, we can use cdk BreakpointObserver, and then we can set itemSize dynamically.

::ng-deep{
    .cdk-virtual-scroll-content-wrapper {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;

        @media (max-width: 991.98px) {
            grid-template-columns: 1fr 1fr;
        }
        @media (max-width: 575.98px) {
            grid-template-columns: 1fr;
        }
    }
}
constructor() {
    const layoutChanges = breakpointObserver.observe([
                '(max-width: 991.98px) and (min-width: 576px)',
                '(max-width: 575.98px)'
            ]);
    layoutChanges.pipe(takeUntil(this.destroy$))
    .subscribe(res => {
        this.tabletScreen = breakpointObserver.isMatched('(max-width: 991.98px) and (min-width: 576px)');
        this.mobileScreen = breakpointObserver.isMatched('(max-width: 575.98px)');
        this.itemSize = 360 / 3;    // grid-template-columns: 1fr 1fr 1fr; --------- 360px  = item height 
        if (this.tabletScreen) {
            this.itemSize = 360 / 2;   //  grid-template-columns: 1fr 1fr;
        }
        if (this.mobileScreen) {
            this.itemSize = 360;      //  grid-template-columns: 1fr;
        }
    });
}

@coldiary
Copy link

In the meantime you can use display:grid by overriding the css

::ng-deep{
  .cdk-virtual-scroll-content-wrapper {
    display: grid;
    grid-template-columns: 50% 50%;
  }
}

@tdhulster, @mmalerba
This is a good solution, I think

Particularly, we should set itemSize
<cdk-virtual-scroll-viewport [itemSize]="itemSize">
If you want 2 columns per row then itemSize = half value of size (in pixels)
For the responsiveness, we can use cdk BreakpointObserver, and then we can set itemSize dynamically.

::ng-deep{
    .cdk-virtual-scroll-content-wrapper {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;

        @media (max-width: 991.98px) {
            grid-template-columns: 1fr 1fr;
        }
        @media (max-width: 575.98px) {
            grid-template-columns: 1fr;
        }
    }
}
constructor() {
    const layoutChanges = breakpointObserver.observe([
                '(max-width: 991.98px) and (min-width: 576px)',
                '(max-width: 575.98px)'
            ]);
    layoutChanges.pipe(takeWhile(() => this.alive))
    .subscribe(res => {
        this.tabletScreen = breakpointObserver.isMatched('(max-width: 991.98px) and (min-width: 576px)');
        this.mobileScreen = breakpointObserver.isMatched('(max-width: 575.98px)');
        this.itemSize = 360 / 3;    // grid-template-columns: 1fr 1fr 1fr; --------- 360px  = item height 
        if (this.tabletScreen) {
            this.itemSize = 360 / 2;   //  grid-template-columns: 1fr 1fr;
        }
        if (this.mobileScreen) {
            this.itemSize = 360;      //  grid-template-columns: 1fr;
        }
    });
}

I found it does not quite work, as while scroll past the itemSize, the component will unload one item of the viewport from the start, thus breaking the grid flow.

@enesien chunks solution works best, as it would remove a complete row at once.

@dtomaszewski
Copy link

Hi, is there any progress on this issue ?

@Sampath-Lokuge
Copy link

Yes, we must really need this feature with the Angular Virtual scroller component. At this moment Angular doesn't have any such 2 column grid system scroller. This is a huge issue, especially for large data sets with mobile devices. All other/3rd party component providers also heavily or only depend on Angular Virtual scroller. So we need this from Google Angular team. Any news about progress on this in 2022, please?

@Lexa950609
Copy link

Hi,, any update on above??

@zip-fa
Copy link

zip-fa commented Aug 23, 2022

Bump. Any news? Waiting for grid support.
Btw found new lib solving this issue: https://github.com/lVlyke/lithium-ngx-virtual-scroll

@gelinger777
Copy link

bump

@tdhulster
Copy link

Are there people interested in developing this together in pair/ensemble maybe?

@lincolnthree
Copy link

lincolnthree commented Apr 4, 2023

Bump again. Really need this.

Bump. Any news? Waiting for grid support. Btw found new lib solving this issue: https://github.com/lVlyke/lithium-ngx-virtual-scroll

I'm VERY impressed with this library. It's simple, fairly thin / not a huge dependency, and actually works quite well for the purpose. I think it could use a few small tweaks, but so far in my testing it's been very consistent across browsers. I do not know how well supported it will be on older browsers/devices, since it uses ResizeObserver - but I suspect a simple polyfill would take care of that. It does not use any fancy css, either.

@iakovoszournatzis
Copy link

any news?

@Sampath-Lokuge
Copy link

Here is a great library for this feature. Please give a git Star to that super-talented guy if you'll use it.

Ref: https://github.com/lVlyke/lithium-ngx-virtual-scroll#readme

@kirill-borisyonok
Copy link

@mgechev please, add this function

@ultimathei
Copy link

up

@ecancil
Copy link

ecancil commented Jul 3, 2024

This was opened in 2018. That's a little shocking. Can't believe the grid-list can't even dogfood angulars own virtual scrolling

reboot25 pushed a commit to reboot25/components that referenced this issue Jul 11, 2024
Add virtual scroll support to multiple columns per row

Fixes angular#10114
reboot25 pushed a commit to reboot25/components that referenced this issue Jul 11, 2024
Add virtual scroll support to multiple columns per row

Fixes angular#10114
@reboot25
Copy link

reboot25 commented Jul 11, 2024

Yes, I'd be happy to accept a community PR for this. Before you get to far though, it would be good to agree on what the API will look like

I implemented MultiColumnVirtualScrollStrategy similar to the FixedSizeVirtualScrollStrategy to achieve this, and here is the demo: https://storybook.jyuan.online/?path=/story/list--multiple-columns. Can I create a PR for this?

reboot25 added a commit to reboot25/components that referenced this issue Jul 11, 2024
Add virtual scroll support to multiple columns per row

Fixes angular#10114
@lincolnthree
Copy link

lincolnthree commented Jul 11, 2024

Yes, I'd be happy to accept a community PR for this. Before you get to far though, it would be good to agree on what the API will look like

I implemented MultiColumnVirtualScrollStrategy similar to the FixedSizeVirtualScrollStrategy to achieve this, and here is the demo: https://cv.jyuan.online/?path=/story/list--multiple-columns. Can I create a PR for this?

Nice. Does this automatically calculate viewport height? I've been using https://github.com/lVlyke/lithium-ngx-virtual-scroll as someone in this thread previously recommended.

@reboot25
Copy link

@lincolnthree I wrote this according to https://material.angular.io/cdk/scrolling/overview#scrolling-strategies. So it should has the same behavior as FixedSizeVirtualScrollStrategy. In the demo, the viewport height is 100%.

reboot25 added a commit to reboot25/components that referenced this issue Jul 16, 2024
Add virtual scroll support to multiple columns per row

Fixes angular#10114
reboot25 added a commit to reboot25/components that referenced this issue Jul 18, 2024
Add virtual scroll support to multiple columns per row. The viewport will list items with flex-wrap styles, and the width of each item has two types of values: fixed pixel and percentage. For example, {width: 200, height: 50} and {width: '25%', height: 50}.

Fixes angular#10114
@reboot25
Copy link

reboot25 commented Jul 18, 2024

Hi @mmalerba,

I merged the latest main branch and added a demo on the dev pages. I also added support to specify the item width in percentages.

Please check the animation below and give some suggestions. It's not a virtual scroll on a grid; it's just list items using flex-wrap that automatically calculate the viewport height and render visible items in view.

Screenshots from https://material-dev.jyuan.online/virtual-scroll
fixed-width
percentage-width

reboot25 added a commit to reboot25/components that referenced this issue Jul 18, 2024
Add virtual scroll support to multiple columns per row. The viewport will list items with flex-wrap styles, and the width of each item has two types of values: fixed pixel and percentage. For example, {width: 200, height: 50} and {width: '25%', height: 50}.

Fixes angular#10114
@reboot25 reboot25 linked a pull request Jul 18, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: cdk/scrolling feature This issue represents a new feature or feature request rather than a bug or bug fix P3 An issue that is relevant to core functions, but does not impede progress. Important, but not urgent
Projects
None yet
Development

Successfully merging a pull request may close this issue.