Components: virtual-scroll: support multiple items per row

Created on 23 Feb 2018  路  25Comments  路  Source: angular/components

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

P3 cdscrolling feature

Most helpful comment

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

All 25 comments

@mmalerba any news about this?

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

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

Thanks!

+1 this would be amazing

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

please give any update of possible

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%;
  }
}

Any update on this?

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

We solve it with modulo operator...

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

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)

We solve it with modulo operator...

can you give some more information on that?

Up

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.)

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>

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

Any Update on this?

?

That would be a really helpful feature. Trying to build a responsive resizable css grid gallery with virtual scroll. Thanks!

@mmalerba would you accept any PRs on this issue?

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 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.

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

get it work.

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

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;
        }
    });
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

savaryt picture savaryt  路  3Comments

RoxKilly picture RoxKilly  路  3Comments

constantinlucian picture constantinlucian  路  3Comments

alanpurple picture alanpurple  路  3Comments

theunreal picture theunreal  路  3Comments