Angular Material VirtualScrollViewPort - 异步加载数据
Angular Material VirtualScrollViewPort - load data async
我为 VirtualScrollViewPort 找到了不同的样本,但我仍然不知道如何在现实生活中使用它们。样本一次从服务器加载全部数据 - 但由于它们太大,我想单独加载它们。我的主要要求是:
- 搜索掩码 - 用户输入一些数据
- 显示进度条...
- 在服务器上查询搜索
- 如果没有找到结果 ==> 显示一条消息
- 如果找到东西 ==> 显示前 n (=10) 个项目
- 用户向下滚动后,仅例如还剩 5 件 ==> 额外加载 10 件
- 继续 5。
- 如果只是例如还剩 3 ==> 结束滚动
我已经尝试了 Specifying data
部分的方法 - 但我无法识别没有加载数据并且我无法启动视图 - 特别是当用户重置内容时。
我也试过
<cdk-virtual-scroll-viewport itemSize="itemHeight" (scrolledIndexChange)="nextBatch($event,(resultList[resultList.length-1].total) )"
class="scroll-container">
<div *cdkVirtualFor="let search of resultList" class="card-item" >
适用于第一个要求,但最终我失败了 scrolledIndexChange
仅在列表中的第一项上被触发。我不知道如何跟踪用户是否已经在显示第 6 项(这将加载其他数据)。在 API page 上,我在 scrolledIndexChange
旁边没有看到任何 @Output()
。
有什么提示可以正确跟踪事件吗?
更新
我发现的第一个问题是设置高度的语法不正确,即 [itemSize]="itemHeight"
是合适的语法,否则它始终保持为零 ==> 所有元素都被渲染!
经过一些工作后,我的最终解决方案如下所示:
<ng-container *ngIf="lstSearchResults|async as resultList; else searching">
<cdk-virtual-scroll-viewport [itemSize]="itemHeight" (scrolledIndexChange)="nextBatch()"
class="scroll-container">
<div *cdkVirtualFor="let search of resultList" class="card-item">
值得注意的是我的列表是一个异步列表,名为 lstSearchResults
并且在 ts
代码中我有:
// for proper height and caching... (in pixels)
itemHeight = 174;
search(searchConfig: SearchOptions): void {
// ....
this.lstSearchResults = new BehaviorSubject<SearchResult[]>(null);
// call the REST service
this.searchService.doSearch(searchConfig).subscribe((foundEntry) => {
if (!this.resultList) {
// first list - nothing found up till now
this.resultList = foundEntry;
} else {
if (!this.resultList[this.resultList.length - 1]) {
//remove the marker (which was added below/previously)
this.resultList.pop();
}
foundEntry.map((item) => this.resultList.push(item));
}
if (this.resultList[0] && this.resultList[0].total > this.resultList.length + 1) {
//some more elements could be fetched from the server ==> add a dummy entry for rendering
this.resultList.push(undefined);
}
// notify the search list to be updated
this.lstSearchResults.next(this.resultList);
});
}
对于滚动,我有以下代码:
nextBatch(): void {
if (this.theEnd) {
return;
}
if (this.resultList[0]) {
// something was found
if (
this.viewport.getRenderedRange().end ===
this.viewport.getDataLength()
) {
// since we scrolled to the very end of the rendered display
// ==> check if further search is required (and do so...)
const searchTotal = this.resultList[0].total;
this.mySearchConfig.posOffset += this.mySearchConfig.noOfElements;
// some basic check if the total counter exceeds the current offset
// i.e. no further search required
if (this.mySearchConfig.posOffset <= searchTotal) {
this.search(this.mySearchConfig, true);
} else {
this.theEnd = true;
}
}
} else {
// nothing found ==> mark the end
this.theEnd = true;
}
}
我为 VirtualScrollViewPort 找到了不同的样本,但我仍然不知道如何在现实生活中使用它们。样本一次从服务器加载全部数据 - 但由于它们太大,我想单独加载它们。我的主要要求是:
- 搜索掩码 - 用户输入一些数据
- 显示进度条...
- 在服务器上查询搜索
- 如果没有找到结果 ==> 显示一条消息
- 如果找到东西 ==> 显示前 n (=10) 个项目
- 用户向下滚动后,仅例如还剩 5 件 ==> 额外加载 10 件
- 继续 5。
- 如果只是例如还剩 3 ==> 结束滚动
我已经尝试了 Specifying data
部分的方法 - 但我无法识别没有加载数据并且我无法启动视图 - 特别是当用户重置内容时。
我也试过
<cdk-virtual-scroll-viewport itemSize="itemHeight" (scrolledIndexChange)="nextBatch($event,(resultList[resultList.length-1].total) )"
class="scroll-container">
<div *cdkVirtualFor="let search of resultList" class="card-item" >
适用于第一个要求,但最终我失败了 scrolledIndexChange
仅在列表中的第一项上被触发。我不知道如何跟踪用户是否已经在显示第 6 项(这将加载其他数据)。在 API page 上,我在 scrolledIndexChange
旁边没有看到任何 @Output()
。
有什么提示可以正确跟踪事件吗?
更新
我发现的第一个问题是设置高度的语法不正确,即 [itemSize]="itemHeight"
是合适的语法,否则它始终保持为零 ==> 所有元素都被渲染!
经过一些工作后,我的最终解决方案如下所示:
<ng-container *ngIf="lstSearchResults|async as resultList; else searching">
<cdk-virtual-scroll-viewport [itemSize]="itemHeight" (scrolledIndexChange)="nextBatch()"
class="scroll-container">
<div *cdkVirtualFor="let search of resultList" class="card-item">
值得注意的是我的列表是一个异步列表,名为 lstSearchResults
并且在 ts
代码中我有:
// for proper height and caching... (in pixels)
itemHeight = 174;
search(searchConfig: SearchOptions): void {
// ....
this.lstSearchResults = new BehaviorSubject<SearchResult[]>(null);
// call the REST service
this.searchService.doSearch(searchConfig).subscribe((foundEntry) => {
if (!this.resultList) {
// first list - nothing found up till now
this.resultList = foundEntry;
} else {
if (!this.resultList[this.resultList.length - 1]) {
//remove the marker (which was added below/previously)
this.resultList.pop();
}
foundEntry.map((item) => this.resultList.push(item));
}
if (this.resultList[0] && this.resultList[0].total > this.resultList.length + 1) {
//some more elements could be fetched from the server ==> add a dummy entry for rendering
this.resultList.push(undefined);
}
// notify the search list to be updated
this.lstSearchResults.next(this.resultList);
});
}
对于滚动,我有以下代码:
nextBatch(): void {
if (this.theEnd) {
return;
}
if (this.resultList[0]) {
// something was found
if (
this.viewport.getRenderedRange().end ===
this.viewport.getDataLength()
) {
// since we scrolled to the very end of the rendered display
// ==> check if further search is required (and do so...)
const searchTotal = this.resultList[0].total;
this.mySearchConfig.posOffset += this.mySearchConfig.noOfElements;
// some basic check if the total counter exceeds the current offset
// i.e. no further search required
if (this.mySearchConfig.posOffset <= searchTotal) {
this.search(this.mySearchConfig, true);
} else {
this.theEnd = true;
}
}
} else {
// nothing found ==> mark the end
this.theEnd = true;
}
}