I know your question is about ngx-virtual-scroller, but I have a solution for ngx-ui-scroll, which might be helpful for you or someone who deals with dataset grouping. Big part of the logic seems independent of the scroller implementation/api, but let me think I'm doing it for ngx-ui-scroll.
In this case we need to treat groups
as the datasource which should implement get
method in accordance with ngx-ui-scroll docs. Like following
groups = new Datasource({
get: (index, count, success) =>
success(this.getItems(index, count)
)
})
I don't know the structure of your data, and this should not be important because we are discussing the approach. The only thing we need to take into account is a consistency between the Datasource and the template. Imagine we already have flat items dataset of fixed length
data = [];
MIN = 1;
MAX = 200;
constructor() {
for (let i = this.MIN; i <= this.MAX; i++) {
this.data.push({ id: i, text: 'item #' + i });
}
}
And you want to group them. How may groups you'll have? It depends on how many items you want to be in a single group.
this.ITEMS_PER_GROUP = 3;
this.groupsCount = Math.ceil((this.MAX - this.MIN) / this.ITEMS_PER_GROUP);
Then going back to getItems
implementation, I'd suggest to split items retrieving procedure into 2 methods. Getting groups (by index-count due to ngx-ui-scroll api):
getItems(index: number, count: number) {
const data = [];
const start = Math.max(1, index);
const end = Math.min(this.groupsCount, index + count - 1);
if (start <= end) {
for (let i = start; i <= end; i++) {
const group = this.getGroup(i);
if (group) {
data.push(group);
}
}
}
return data;
}
and getting one group by index:
getGroup(index: number) {
let result = null;
const data = [];
const start = this.MIN + (index - 1) * this.ITEMS_PER_GROUP;
const end = start + this.ITEMS_PER_GROUP - 1;
if (start <= end) {
for (let i = start; i <= end; i++) {
const item = this.data.find(item => item.id === i);
if (item) {
data.push(item);
}
}
result = {
title: 'Group ' + index,
items: data
};
}
return result;
}
This way you'll get the datasource consistent with what you need in the template layer. With ngx-ui-scroll it will look as following:
<div *uiScroll="let group of groups">
<div>{{group.title}}</div>
<div *ngFor="let item of group.items">
<div class="item">{{item.text}}</div>
</div>
</div>
Speaking of ngx-ui-scroll, all limitations could be removed, I mean you may not know the boundaries of the dataset and groups count, but the implementation would be slightly different.
At last, I created demo, as the case seems useful for ngx-ui-scroll users
https://stackblitz.com/edit/angular-ngx-ui-scroll-1-3-4-grouping-datasource