@acorex/cdk 22.2.0-next.0 → 22.2.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1168,6 +1168,7 @@ class AXListDataSource extends DataSource {
1168
1168
  this.config = config;
1169
1169
  this.debounceTime = 0;
1170
1170
  this.subscription = new Subscription();
1171
+ this.connected = false;
1171
1172
  this._range = { start: 0, end: 0 };
1172
1173
  this.source = config.source;
1173
1174
  if (config.debounceTime)
@@ -1176,9 +1177,15 @@ class AXListDataSource extends DataSource {
1176
1177
  this.dataStream = new BehaviorSubject(this.config.source.cachedItems);
1177
1178
  this.source.onChanged.subscribe((data) => {
1178
1179
  this.dataStream.next(data.cachedItems);
1180
+ // A refresh (e.g. a new search) only reloads page 0. When the rendered range stays the same,
1181
+ // CDK emits no `viewChange`, so the other visible pages would otherwise stay as loading rows.
1182
+ if (this.connected) {
1183
+ this.loadMissingPagesInRange(data.totalCount);
1184
+ }
1179
1185
  });
1180
1186
  }
1181
1187
  connect(collectionViewer) {
1188
+ this.connected = true;
1182
1189
  this.subscription.add(collectionViewer.viewChange
1183
1190
  .pipe(debounceTime(this.debounceTime))
1184
1191
  .pipe(distinctUntilChanged())
@@ -1193,8 +1200,22 @@ class AXListDataSource extends DataSource {
1193
1200
  return this.dataStream;
1194
1201
  }
1195
1202
  disconnect() {
1203
+ this.connected = false;
1196
1204
  this.subscription.unsubscribe();
1197
1205
  }
1206
+ loadMissingPagesInRange(totalCount) {
1207
+ const end = Math.min(this._range.end, totalCount);
1208
+ if (end <= this._range.start) {
1209
+ return;
1210
+ }
1211
+ const startPage = this.getPageForIndex(this._range.start);
1212
+ const endPage = this.getPageForIndex(end - 1);
1213
+ for (let i = startPage; i <= endPage; i++) {
1214
+ if (!this.source.isPageFetched(i)) {
1215
+ this.source.setPage(i);
1216
+ }
1217
+ }
1218
+ }
1198
1219
  getPageForIndex(index) {
1199
1220
  return Math.floor(index / this.source.config.pageSize);
1200
1221
  }
@@ -1231,6 +1252,9 @@ class AXDataSource {
1231
1252
  this._totalCount = 0;
1232
1253
  this._items = [];
1233
1254
  this.fetchedPages = new Set();
1255
+ /** Bumped on every reset so responses requested before it are dropped instead of corrupting the cache. */
1256
+ this.loadGeneration = 0;
1257
+ this.pendingLoads = 0;
1234
1258
  this._page = 0;
1235
1259
  this._query = { skip: 0, take: 0, sort: [] };
1236
1260
  this.onChanged = new Subject();
@@ -1248,6 +1272,8 @@ class AXDataSource {
1248
1272
  if (this.fetchedPages.has(page) && this.useCache) {
1249
1273
  return;
1250
1274
  }
1275
+ const generation = this.loadGeneration;
1276
+ this.pendingLoads++;
1251
1277
  this.setLoadingState(true);
1252
1278
  this.fetchedPages.add(page);
1253
1279
  this._query.take = this.config.pageSize;
@@ -1255,25 +1281,50 @@ class AXDataSource {
1255
1281
  this.config
1256
1282
  .load({ ...this._query })
1257
1283
  .then((result) => {
1258
- if (this._totalCount != result.total) {
1259
- this._cachedItems = new Array(result.total);
1260
- this._totalCount = result.total;
1284
+ if (generation !== this.loadGeneration) {
1285
+ return;
1261
1286
  }
1262
- this._items = result.items;
1263
- this._cachedItems.splice(page * this.config.pageSize, this.config.pageSize, ...result.items);
1264
- const event = {
1265
- cachedItems: this.cachedItems,
1266
- items: this.items,
1267
- page: page,
1268
- totalCount: this.totalCount,
1269
- totalPages: this.totalPages,
1270
- };
1271
- this.onChanged.next(event);
1287
+ this.applyLoadResult(page, result);
1288
+ }, (error) => {
1289
+ if (generation === this.loadGeneration) {
1290
+ this.fetchedPages.delete(page);
1291
+ }
1292
+ throw error;
1272
1293
  })
1273
1294
  .finally(() => {
1274
- this.setLoadingState(false);
1295
+ if (generation !== this.loadGeneration) {
1296
+ return;
1297
+ }
1298
+ this.pendingLoads = Math.max(0, this.pendingLoads - 1);
1299
+ if (this.pendingLoads === 0) {
1300
+ this.setLoadingState(false);
1301
+ }
1275
1302
  });
1276
1303
  }
1304
+ applyLoadResult(page, result) {
1305
+ if (this._totalCount != result.total) {
1306
+ if (this._totalCount > 0) {
1307
+ // Rows of other pages are dropped with the old array, so they must be fetched again.
1308
+ this.fetchedPages = new Set([page]);
1309
+ }
1310
+ this._cachedItems = new Array(result.total);
1311
+ this._totalCount = result.total;
1312
+ }
1313
+ this._items = result.items;
1314
+ this._cachedItems.splice(page * this.config.pageSize, this.config.pageSize, ...result.items);
1315
+ const event = {
1316
+ cachedItems: this.cachedItems,
1317
+ items: this.items,
1318
+ page: page,
1319
+ totalCount: this.totalCount,
1320
+ totalPages: this.totalPages,
1321
+ };
1322
+ this.onChanged.next(event);
1323
+ }
1324
+ /** Whether `page` was loaded (or is loading) for the current filter/sort. */
1325
+ isPageFetched(page) {
1326
+ return this.fetchedPages.has(page);
1327
+ }
1277
1328
  async getItemsByFilter(filter) {
1278
1329
  return await this.config.load({ ...this.query, filter });
1279
1330
  }
@@ -1282,7 +1333,7 @@ class AXDataSource {
1282
1333
  this.onLoadingChanged.next(this._isLoading);
1283
1334
  }
1284
1335
  setPage(page) {
1285
- if (this._page != page || this._items.length == 0) {
1336
+ if (this._page != page || this._items.length == 0 || !this.fetchedPages.has(page)) {
1286
1337
  this._page = page;
1287
1338
  this.load();
1288
1339
  }
@@ -1301,12 +1352,22 @@ class AXDataSource {
1301
1352
  this._query.filter = null;
1302
1353
  }
1303
1354
  reset() {
1355
+ const wasLoading = this._isLoading;
1356
+ this.resetState();
1357
+ if (wasLoading) {
1358
+ this.setLoadingState(false);
1359
+ }
1360
+ }
1361
+ /** Resets paging state without emitting `onLoadingChanged`, so a following `load()` keeps the loading state continuous. */
1362
+ resetState() {
1304
1363
  this._query.filter = null;
1305
1364
  this._query.sort = [];
1306
1365
  this._query.skip = 0;
1307
1366
  this._items = new Array(0);
1308
1367
  this._cachedItems = new Array(this.config.pageSize);
1309
1368
  this.fetchedPages.clear();
1369
+ this.loadGeneration++;
1370
+ this.pendingLoads = 0;
1310
1371
  this._page = 0;
1311
1372
  this._totalCount = 0;
1312
1373
  }
@@ -1314,7 +1375,7 @@ class AXDataSource {
1314
1375
  const currentFilter = this._query.filter;
1315
1376
  const currentSort = this._query.sort;
1316
1377
  if (options.reset) {
1317
- this.reset();
1378
+ this.resetState();
1318
1379
  }
1319
1380
  this._query.filter = currentFilter;
1320
1381
  this._query.sort = currentSort;