Skip to content

Commit 9628a20

Browse files
authored
Collections: get rid of correction index in live_update extension (T940677, T1141769, T1083476) (DevExpress#30241)
1 parent 1ea69fb commit 9628a20

File tree

3 files changed

+71
-63
lines changed

3 files changed

+71
-63
lines changed

packages/devextreme/js/__internal/ui/collection/m_collection_widget.live_update.ts

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ class CollectionWidgetLiveUpdate<
2121
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2222
TKey = any,
2323
> extends CollectionWidgetAsync<TProperties> {
24-
_correctionIndex!: number;
25-
2624
_itemsCache!: TItem[];
2725

2826
_getDefaultOptions(): TProperties {
@@ -32,26 +30,11 @@ class CollectionWidgetLiveUpdate<
3230
};
3331
}
3432

35-
_customizeStoreLoadOptions(e) {
36-
const dataController = this._dataController;
37-
38-
if (dataController.getDataSource() && !this._dataController.isLoaded()) {
39-
this._correctionIndex = 0;
40-
}
41-
if (this._correctionIndex && e.storeLoadOptions) {
42-
e.storeLoadOptions.skip += this._correctionIndex;
43-
}
44-
}
45-
46-
reload(): void {
47-
this._correctionIndex = 0;
48-
}
33+
reload(): void { }
4934

5035
_init(): void {
5136
super._init();
5237
this._refreshItemsCache();
53-
this._correctionIndex = 0;
54-
this._subscribeLoadOptionsCustomization(true);
5538
}
5639

5740
_findItemElementByKey(key) {
@@ -160,11 +143,6 @@ class CollectionWidgetLiveUpdate<
160143
}
161144
}
162145

163-
_dispose(): void {
164-
this._subscribeLoadOptionsCustomization(false);
165-
super._dispose();
166-
}
167-
168146
_updateByChange(keyInfo, items, change, isPartialRefresh): void {
169147
if (isPartialRefresh) {
170148
this._renderItem(change.index, change.data, null, this._findItemElementByKey(change.key));
@@ -187,7 +165,6 @@ class CollectionWidgetLiveUpdate<
187165
this._renderItem(change.index ?? items.length, change.data);
188166

189167
this._afterItemElementInserted();
190-
this._correctionIndex++;
191168
});
192169
}
193170

@@ -236,8 +213,6 @@ class CollectionWidgetLiveUpdate<
236213
this._afterItemElementDeleted($removedItemElement, deletedActionArgs);
237214
}
238215
});
239-
240-
this._correctionIndex--;
241216
}
242217
}
243218

@@ -264,19 +239,6 @@ class CollectionWidgetLiveUpdate<
264239
domAdapter.insertElement($container.get(0), $itemFrame.get(0), nextSiblingElement);
265240
}
266241

267-
_subscribeLoadOptionsCustomization(enable: boolean): void {
268-
if (!this._dataController) {
269-
return;
270-
}
271-
272-
if (enable) {
273-
this._correctionIndex = 0;
274-
this._dataController.on('customizeStoreLoadOptions', this._customizeStoreLoadOptions.bind(this));
275-
} else {
276-
this._dataController.off('customizeStoreLoadOptions', this._customizeStoreLoadOptions.bind(this));
277-
}
278-
}
279-
280242
_optionChanged(args: OptionChanged<TProperties>): void {
281243
switch (args.name) {
282244
case 'items': {
@@ -292,9 +254,7 @@ class CollectionWidgetLiveUpdate<
292254
this.option('items', []);
293255
}
294256

295-
this._subscribeLoadOptionsCustomization(false);
296257
super._optionChanged(args);
297-
this._subscribeLoadOptionsCustomization(true);
298258
break;
299259
case 'repaintChangesOnly':
300260
break;

packages/devextreme/testing/tests/DevExpress.ui.widgets/listParts/liveUpdateTests.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import $ from 'jquery';
22
import { DataSource } from 'common/data/data_source/data_source';
33
import ArrayStore from 'common/data/array_store';
4+
import keyboardMock from '../../../helpers/keyboardMock.js';
45

56
import 'ui/list';
67

@@ -744,4 +745,43 @@ QUnit.module('live update', {
744745
assert.equal(list.itemElements().get(0), $itemElements.get(0), 'item element 0 is not rerenderd');
745746
assert.notEqual(list.itemElements().get(1), $itemElements.get(1), 'item element 1 is rerenderd');
746747
});
748+
749+
QUnit.test('repaintChangesOnly, dataSource skip should not be negative on search (T1083476)', function(assert) {
750+
const items = Array.from({ length: 10 }, (_, i) => ({ text: `Item ${i}`, id: i }));
751+
let skipValue = 0;
752+
const $list = $('#list').dxList({
753+
dataSource: {
754+
key: 'id',
755+
pushAggregationTimeout: 0,
756+
load(loadOptions) {
757+
skipValue = loadOptions.skip;
758+
759+
let result = items;
760+
761+
if(loadOptions.searchValue) {
762+
result = result.filter(item =>
763+
String(item[loadOptions.searchExpr])
764+
.toLowerCase()
765+
.includes(String(loadOptions.searchValue).toLowerCase())
766+
);
767+
}
768+
769+
result = result.slice(loadOptions.skip, loadOptions.skip + loadOptions.take);
770+
771+
return result;
772+
}
773+
},
774+
searchEnabled: true,
775+
searchExpr: 'text',
776+
displayExpr: 'text',
777+
repaintChangesOnly: true,
778+
});
779+
780+
const keyboard = keyboardMock($list.find('.dx-texteditor-input').eq(0));
781+
782+
keyboard.type('z');
783+
keyboard.type('z');
784+
785+
assert.strictEqual(skipValue >= 0, true, 'skip value did not become negative');
786+
});
747787
});

packages/devextreme/testing/tests/DevExpress.ui/collectionWidgetParts/liveUpdateTests.js

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class TestComponent extends CollectionWidget {
2323
_itemClass() { return 'item'; }
2424
_itemDataKey() { return '123'; }
2525
_itemContainer() { return this.$element(); }
26-
_shouldAppendItems() { return true; }
26+
_allowDynamicItemsAppend() { return true; }
2727

2828
reload() {
2929
super.reload();
@@ -60,13 +60,16 @@ class LiveUpdateTestHelper {
6060

6161
return new TestComponent(this.$element, options || {
6262
dataSource: new DataSource({
63-
load: (e) => this.data.sort((a, b) => a.index - b.index),
63+
load: () => this.data.sort((a, b) => a.index - b.index),
6464
loadMode: 'raw',
6565
pageSize: 2,
6666
pushAggregationTimeout: 0,
67-
key: 'id'
67+
reshapeOnPush: true,
68+
sort: { field: 'index' },
69+
key: 'id',
6870
}),
69-
onItemDeleting: this.onItemDeletingSpy
71+
repaintChangesOnly: true,
72+
onItemDeleting: this.onItemDeletingSpy,
7073
});
7174
}
7275

@@ -85,29 +88,29 @@ module('live update', {
8588
}, () => {
8689
test('check load next page', function(assert) {
8790
assert.equal(helper.getItems().length, 2);
88-
helper.instance.loadNextPage();
91+
helper.instance._loadNextPage();
8992
assert.equal(helper.getItems()[2], helper.data[2]);
9093
assert.equal(helper.getItems().length, 4);
9194
});
9295

9396
test('correct index after push insert', function(assert) {
9497
helper.store.push([{ type: 'insert', data: { id: 200, text: 'text ' + 200, index: 0 }, index: 0 }]);
95-
helper.instance.loadNextPage();
96-
assert.equal(helper.getItems().length, 5);
98+
helper.instance._loadNextPage();
99+
assert.equal(helper.getItems().length, 4);
97100
assert.equal(helper.getItems()[0].id, 200);
98-
assert.equal(helper.getItems()[4].id, 4);
101+
assert.equal(helper.getItems()[3].id, 2);
99102
});
100103

101-
test('correct index after push \'remove\'', function(assert) {
104+
test('correct index after push remove', function(assert) {
102105
helper.store.push([{ type: 'remove', key: 0 }]);
103-
helper.instance.loadNextPage();
104-
assert.equal(helper.getItems().length, 3);
106+
helper.instance._loadNextPage();
107+
assert.equal(helper.getItems().length, 4);
105108
assert.equal(helper.getItems()[0].id, 1);
106-
assert.equal(helper.getItems()[2].id, 3);
109+
assert.equal(helper.getItems()[1].id, 2);
107110
});
108111

109112
// T723520
110-
test('correct index after push \'remove\' and dataSource reload', function(assert) {
113+
test('correct index after push remove and dataSource reload', function(assert) {
111114
helper.instance._shouldAppendItems = () => false;
112115
helper.instance.getDataSource().pageSize(20);
113116
helper.instance.reload();
@@ -125,13 +128,13 @@ module('live update', {
125128
assert.equal(take, 20);
126129
});
127130

128-
test('fire deleting event after push \'remove\'', function(assert) {
131+
test('fire deleting event after push remove', function(assert) {
129132
assert.equal(helper.onItemDeletingSpy.callCount, 0);
130133
helper.store.push([{ type: 'remove', key: 0 }]);
131134
assert.equal(helper.onItemDeletingSpy.callCount, 1);
132135
});
133136

134-
test('fire dxremove event after push \'remove\'', function(assert) {
137+
test('fire dxremove event after push remove', function(assert) {
135138
const removeSpy = sinon.spy();
136139

137140
$('.dx-item').on('dxremove', removeSpy);
@@ -142,15 +145,15 @@ module('live update', {
142145

143146
test('refresh correct index after reload', function(assert) {
144147
helper.store.push([{ type: 'insert', data: { id: 200, text: 'text ' + 200, index: 0 }, index: 0 }]);
145-
assert.equal(helper.getItems().length, 3);
148+
assert.equal(helper.getItems().length, 2);
146149
helper.instance.reload();
147150
assert.equal(helper.getItems()[0].id, 200);
148151
assert.equal(helper.getItems()[1].id, 0);
149152
assert.equal(helper.getItems().length, 2);
150153
assert.equal(helper.instance.itemElements().length, 2);
151154
});
152155

153-
test('item is pushed to the end of store\'s array', function(assert) {
156+
test('item is pushed to the end of store array', function(assert) {
154157
helper.store.push([{ type: 'insert', data: { id: 200, text: 'text ' + 200, index: 0 }, index: 0 }]);
155158
assert.equal(helper.data.pop().id, 200);
156159
});
@@ -168,7 +171,8 @@ module('live update', {
168171
helper.reinitializeWithOptions({
169172
dataSource: {
170173
store,
171-
paginate: true
174+
paginate: true,
175+
reshapeOnPush: true,
172176
},
173177
displayExpr: 'text',
174178
repaintChangesOnly: true
@@ -190,6 +194,7 @@ module('live update', {
190194
loadMode: 'raw',
191195
pageSize: 2,
192196
pushAggregationTimeout: 0,
197+
reshapeOnPush: true,
193198
key: 'id'
194199
});
195200
helper.instance.option('dataSource', newDataSource);
@@ -202,27 +207,30 @@ module('live update', {
202207
newDataSource.store().push([{ type: 'remove', key: 0 }]);
203208

204209
items = helper.getItems();
205-
assert.strictEqual(items.length, 1, '1 item on the first page after remove');
210+
assert.strictEqual(items.length, 2, '2 item on the first page after remove');
206211
assert.strictEqual(items[0].id, 1, '1 item');
207212

208-
helper.instance.loadNextPage();
213+
helper.instance._loadNextPage();
209214

210215
items = helper.getItems();
211-
assert.strictEqual(items.length, 3, '2 pages are loaded');
216+
assert.strictEqual(items.length, 4, '2 pages are loaded');
212217
assert.strictEqual(items[0].id, 1, '1 item');
213218
assert.strictEqual(items[1].id, 2, '2 item');
214219
assert.strictEqual(items[2].id, 3, '3 item');
220+
assert.strictEqual(items[3].id, 4, '4 item');
215221
});
216222

217223
test('dataSource runtime change should be correct even if remove was pushed to the previous dataSource', function(assert) {
218224
const data = [...helper.data];
225+
219226
helper.store.push([{ type: 'remove', key: 0 }]);
220227

221228
const newDataSource = new DataSource({
222229
load: (e) => data.sort((a, b) => a.index - b.index),
223230
loadMode: 'raw',
224231
pageSize: 2,
225232
pushAggregationTimeout: 0,
233+
reshapeOnPush: true,
226234
key: 'id'
227235
});
228236
helper.instance.option('dataSource', newDataSource);
@@ -231,7 +239,7 @@ module('live update', {
231239
assert.strictEqual(items[0].id, 0, '0 item');
232240
assert.strictEqual(items[1].id, 1, '1 item');
233241

234-
helper.instance.loadNextPage();
242+
helper.instance._loadNextPage();
235243

236244
items = helper.getItems();
237245
assert.strictEqual(items[2].id, 2, '2 item');

0 commit comments

Comments
 (0)