0

When using the cdk virtual viewport, need to set the height of the viewport

.example-viewport {
  height: 800px;
  width: 100%;
  border: 1px solid black;
}
<cdk-virtual-scroll-viewport class="example-viewport">
  <div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
</cdk-virtual-scroll-viewport>

But i want the cdk-virtual-scroll-viewport to have wrap the content items if it is not reaching max height to appear scrollbar. But the viewport is not working with max-height.

If there is no horizontal scrollbar, then the viewport sets with height to maximum height is ok. But in my current design UI, i need to show the horizontal scrollbar because lots of content columns like below attached image.

enter image description here

Then the scroll bar is far below due to the height of the viewport. The row items will increase by time, but before the items are increased to max height, i want the horizontal scrollbar wrap to the content height, but currently seems not able to achieve.

The reason i don't use mat-table is that the i want to support infinite scrolling and render the items that fit to screen. Mat-table doesn't support this, if i continue scroll down and request data, the rows items increased in the template and impact on performance.

Anyone has better suggestion?

Thanks a lot.

rodent_la
  • 781
  • 1
  • 11
  • 29

1 Answers1

1

I got a fix which considers the number of elements in the list to set the container height. It calculates the amount of height for the container until it reaches the final height value. Follow these steps and let me know.

1. Keep a reference of cdk-virtual-scroll-viewport in your component

We need this to be able to call checkViewportSize later and make CdkVirtualScrollViewport to recalculate its internal sizes.

Component

@ViewChild('scrollViewport')
private cdkVirtualScrollViewport;

Template

<cdk-virtual-scroll-viewport class="example-viewport" #scrollViewport>
...
</cdk-virtual-scroll-viewport>

2. Calculate the list container height based on the number of elements in the list

Component

calculateContainerHeight(): string {
  const numberOfItems = this.items.length;
  // This should be the height of your item in pixels
  const itemHeight = 20;
  // The final number of items you want to keep visible
  const visibleItems = 10;

  setTimeout(() => {
    // Makes CdkVirtualScrollViewport to refresh its internal size values after 
    // changing the container height. This should be delayed with a "setTimeout"
    // because we want it to be executed after the container has effectively 
    // changed its height. Another option would be a resize listener for the 
    // container and call this line there but it may requires a library to detect 
    // the resize event.

    this.cdkVirtualScrollViewport.checkViewportSize();
  }, 300);

  // It calculates the container height for the first items in the list
  // It means the container will expand until it reaches `200px` (20 * 10)
  // and will keep this size.
  if (numberOfItems <= visibleItems) {
    return `${itemHeight * numberOfItems}px`;
  }

  // This function is called from the template so it ensures the container will have 
  // the final height if number of items are greater than the value in "visibleItems".
  return `${itemHeight * visibleItems}px`;
}

Template

<div [style.height]="calculateContainerHeight()">
  <cdk-virtual-scroll-viewport class="example-viewport" #scrollViewport>
    <div *cdkVirtualFor="let item of items" class="example-item">{{item}}</div>
  </cdk-virtual-scroll-viewport>
</div>

It should be all. You only need to tweak itemHeight and visibleItems in the function according to your circumstances to get the result you're expecting.