Skip to content

Commit 2ccc7fc

Browse files
authored
feat: add new setData() function (#464)
1 parent 00c7f71 commit 2ccc7fc

5 files changed

Lines changed: 191 additions & 1 deletion

File tree

packages/demo/src/app-routing.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import Methods09 from './methods/methods09.js';
3030
import Methods10 from './methods/methods10.js';
3131
import Methods11 from './methods/methods11.js';
3232
import Methods12 from './methods/methods12.js';
33+
import Methods13 from './methods/methods13.js';
3334
import Options01 from './options/options01.js';
3435
import Options02 from './options/options02.js';
3536
import Options03 from './options/options03.js';
@@ -165,6 +166,7 @@ export const exampleRouting = [
165166
{ name: 'methods10', view: '/src/methods/methods10.html', viewModel: Methods10, title: 'The refresh' },
166167
{ name: 'methods11', view: '/src/methods/methods11.html', viewModel: Methods11, title: 'The destroy' },
167168
{ name: 'methods12', view: '/src/methods/methods12.html', viewModel: Methods12, title: 'The getData' },
169+
{ name: 'methods13', view: '/src/methods/methods13.html', viewModel: Methods13, title: 'The setData' },
168170
],
169171
},
170172
{
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<div class="row mb-2">
2+
<div class="col-md-12 title-desc">
3+
<h2 class="bd-title">
4+
The setData
5+
<span class="float-end links">
6+
Code <span class="fa fa-link"></span>
7+
<span class="small">
8+
<a target="_blank" href="https://github.com/ghiscoding/multiple-select-vanilla/blob/main/packages/demo/src/methods/methods13.html"
9+
>html</a
10+
>
11+
|
12+
<a target="_blank" href="https://github.com/ghiscoding/multiple-select-vanilla/blob/main/packages/demo/src/methods/methods13.ts"
13+
>ts</a
14+
>
15+
</span>
16+
</span>
17+
</h2>
18+
<div class="demo-subtitle">
19+
Use <code>multipleSelect('select').setData([/*data*/])</code> to update the loaded data.
20+
</div>
21+
</div>
22+
</div>
23+
24+
<div>
25+
<div class="mb-3 row">
26+
<label class="col-sm-2">Methods</label>
27+
<div class="col-sm-10">
28+
<button id="setData-basic" class="btn btn-secondary">setData (basic array)</button>
29+
<button id="setData-object" class="btn btn-secondary">setData (object)</button>
30+
<button id="setData-string" class="btn btn-secondary">setData (string array)</button>
31+
<button id="setData-group" class="btn btn-secondary">setData (group array)</button>
32+
</div>
33+
</div>
34+
35+
<div class="mb-3 row">
36+
<label class="col-sm-2">Basic Select</label>
37+
<div class="col-sm-10">
38+
<select multiple="multiple" class="full-width">
39+
<option value="text1">text1</option>
40+
<option value="text2">text2</option>
41+
<option value="text3">text3</option>
42+
</select>
43+
</div>
44+
</div>
45+
</div>
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { type MultipleSelectInstance, multipleSelect, type OptGroupRowData, type OptionRowData } from 'multiple-select-vanilla';
2+
3+
export default class Example {
4+
ms1?: MultipleSelectInstance;
5+
6+
mount() {
7+
this.ms1 = multipleSelect('select', {
8+
filter: true,
9+
}) as MultipleSelectInstance;
10+
11+
// Basic array
12+
document.querySelector('#setData-basic')!.addEventListener('click', () => {
13+
const newData = [
14+
{ text: 'Basic One', value: 'basic1' },
15+
{ text: 'Basic Two', value: 'basic2' },
16+
{ text: 'Basic Three', value: 'basic3' },
17+
];
18+
this.ms1!.setData(newData);
19+
});
20+
21+
// Object
22+
document.querySelector('#setData-object')!.addEventListener('click', () => {
23+
const newData = {
24+
obj1: 'Object One',
25+
obj2: 'Object Two',
26+
obj3: 'Object Three',
27+
};
28+
this.ms1!.setData(newData);
29+
});
30+
31+
// String array
32+
document.querySelector('#setData-string')!.addEventListener('click', () => {
33+
const newData = ['String One', 'String Two', 'String Three'];
34+
this.ms1!.setData(newData);
35+
});
36+
37+
// Group array
38+
document.querySelector('#setData-group')!.addEventListener('click', () => {
39+
const newData: OptGroupRowData[] = [
40+
{
41+
type: 'optgroup',
42+
label: 'Group 1',
43+
children: [
44+
{ text: 'Group One', value: 'group1', type: 'option' } as OptionRowData,
45+
{ text: 'Group Two', value: 'group2', type: 'option' } as OptionRowData,
46+
],
47+
},
48+
{
49+
type: 'optgroup',
50+
label: 'Group 2',
51+
children: [{ text: 'Group Three', value: 'group3', type: 'option' } as OptionRowData],
52+
},
53+
];
54+
this.ms1!.setData(newData);
55+
});
56+
}
57+
58+
unmount() {
59+
// destroy ms instance(s) to avoid DOM leaks
60+
this.ms1?.destroy();
61+
this.ms1 = undefined;
62+
}
63+
}

packages/multiple-select-vanilla/src/MultipleSelectInstance.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @author zhixin wen <wenzhixin2010@gmail.com>
33
*/
44
import Constants from './constants.js';
5-
import type { HtmlStruct, OptGroupRowData, OptionDataObject, OptionRowData } from './models/interfaces.js';
5+
import type { CollectionData, HtmlStruct, OptGroupRowData, OptionDataObject, OptionRowData } from './models/interfaces.js';
66
import type { MultipleSelectLocale, MultipleSelectLocales } from './models/locale.interface.js';
77
import type { ClickedGroup, ClickedOption, CloseReason, MultipleSelectOption } from './models/multipleSelectOption.interface.js';
88
import { BindingEventService } from './services/binding-event.service.js';
@@ -1805,6 +1805,21 @@ export class MultipleSelectInstance {
18051805
this._checkAll(false);
18061806
}
18071807

1808+
/**
1809+
* Replace the current data/options with a new data set and re-render the dropdown.
1810+
* @param data - The new data to load (array of options, object, string array, or group array).
1811+
* @param renderFilterAndSearchAll - If true, re-render filter/search UI as well (default: false).
1812+
*/
1813+
setData(data: CollectionData, renderFilterAndSearchAll = false) {
1814+
emptyElement(this.elm);
1815+
this.ulElm?.remove();
1816+
this.options.data = data;
1817+
this.initData();
1818+
this.initList(renderFilterAndSearchAll);
1819+
this.update();
1820+
this.adjustDropSizeAndPosition();
1821+
}
1822+
18081823
protected _checkAll(checked: boolean, ignoreUpdate?: boolean) {
18091824
for (const row of this.data || []) {
18101825
if ((row as OptGroupRowData).type === 'optgroup') {

playwright/e2e/methods13.spec.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { expect, test } from '@playwright/test';
2+
3+
test.describe('Methods 13 - setData()', () => {
4+
test('should update options and data length after setData (basic array)', async ({ page }) => {
5+
await page.goto('#/methods13');
6+
await page.locator('.ms-parent').click();
7+
await expect(page.locator('.ms-drop li:visible')).toHaveCount(3);
8+
await expect(page.locator('span').filter({ hasText: 'text1' })).toBeVisible();
9+
await expect(page.locator('span').filter({ hasText: 'text2' })).toBeVisible();
10+
await expect(page.locator('span').filter({ hasText: 'text3' })).toBeVisible();
11+
await page.getByRole('button', { name: /setData \(basic array\)/ }).click();
12+
await page.locator('.ms-parent').click();
13+
await expect(page.locator('.ms-drop li:visible')).toHaveCount(3);
14+
await expect(page.locator('span').filter({ hasText: 'Basic One' })).toBeVisible();
15+
await expect(page.locator('span').filter({ hasText: 'Basic Two' })).toBeVisible();
16+
await expect(page.locator('span').filter({ hasText: 'Basic Three' })).toBeVisible();
17+
});
18+
19+
test('should update options and data length after setData (object)', async ({ page }) => {
20+
await page.goto('#/methods13');
21+
await page.locator('.ms-parent').click();
22+
await expect(page.locator('.ms-drop li:visible')).toHaveCount(3);
23+
await expect(page.locator('span').filter({ hasText: 'text1' })).toBeVisible();
24+
await expect(page.locator('span').filter({ hasText: 'text2' })).toBeVisible();
25+
await expect(page.locator('span').filter({ hasText: 'text3' })).toBeVisible();
26+
await page.getByRole('button', { name: /setData \(object\)/ }).click();
27+
await page.locator('.ms-parent').click();
28+
await expect(page.locator('.ms-drop li:visible')).toHaveCount(3);
29+
await expect(page.locator('span').filter({ hasText: 'Object One' })).toBeVisible();
30+
await expect(page.locator('span').filter({ hasText: 'Object Two' })).toBeVisible();
31+
await expect(page.locator('span').filter({ hasText: 'Object Three' })).toBeVisible();
32+
});
33+
34+
test('should update options and data length after setData (string array)', async ({ page }) => {
35+
await page.goto('#/methods13');
36+
await page.locator('.ms-parent').click();
37+
await expect(page.locator('.ms-drop li:visible')).toHaveCount(3);
38+
await expect(page.locator('span').filter({ hasText: 'text1' })).toBeVisible();
39+
await expect(page.locator('span').filter({ hasText: 'text2' })).toBeVisible();
40+
await expect(page.locator('span').filter({ hasText: 'text3' })).toBeVisible();
41+
await page.getByRole('button', { name: /setData \(string array\)/ }).click();
42+
await page.locator('.ms-parent').click();
43+
await expect(page.locator('.ms-drop li:visible')).toHaveCount(3);
44+
await expect(page.locator('span').filter({ hasText: 'String One' })).toBeVisible();
45+
await expect(page.locator('span').filter({ hasText: 'String Two' })).toBeVisible();
46+
await expect(page.locator('span').filter({ hasText: 'String Three' })).toBeVisible();
47+
});
48+
49+
test('should update options and data length after setData (group array)', async ({ page }) => {
50+
await page.goto('#/methods13');
51+
await page.locator('.ms-parent').click();
52+
await expect(page.locator('.ms-drop li:visible')).toHaveCount(3);
53+
await expect(page.locator('span').filter({ hasText: 'text1' })).toBeVisible();
54+
await expect(page.locator('span').filter({ hasText: 'text2' })).toBeVisible();
55+
await expect(page.locator('span').filter({ hasText: 'text3' })).toBeVisible();
56+
57+
await page.getByRole('button', { name: /setData \(group array\)/ }).click();
58+
await page.locator('.ms-parent').click();
59+
await expect(page.locator('.ms-drop li.group:visible')).toHaveCount(2);
60+
await expect(page.locator('.ms-drop li:not(.group):visible')).toHaveCount(3);
61+
await expect(page.locator('span').filter({ hasText: 'Group One' })).toBeVisible();
62+
await expect(page.locator('span').filter({ hasText: 'Group Two' })).toBeVisible();
63+
await expect(page.locator('span').filter({ hasText: 'Group Three' })).toBeVisible();
64+
});
65+
});

0 commit comments

Comments
 (0)