Skip to content

Commit a57b2f9

Browse files
committed
[Autocomplete] Restoring the selected value on disconnect
1 parent e6f0966 commit a57b2f9

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed

src/Autocomplete/assets/dist/controller.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,28 @@ class default_1 extends Controller {
6464
}
6565
disconnect() {
6666
this.stopMutationObserver();
67+
let currentSelectedValues = [];
68+
if (this.selectElement) {
69+
if (this.selectElement.multiple) {
70+
currentSelectedValues = Array.from(this.selectElement.options)
71+
.filter((option) => option.selected)
72+
.map((option) => option.value);
73+
}
74+
else {
75+
currentSelectedValues = [this.selectElement.value];
76+
}
77+
}
78+
this.tomSelect.destroy();
79+
if (this.selectElement) {
80+
if (this.selectElement.multiple) {
81+
Array.from(this.selectElement.options).forEach((option) => {
82+
option.selected = currentSelectedValues.includes(option.value);
83+
});
84+
}
85+
else {
86+
this.selectElement.value = currentSelectedValues[0];
87+
}
88+
}
6789
}
6890
getMaxOptions() {
6991
return this.selectElement ? this.selectElement.options.length : 50;

src/Autocomplete/assets/src/controller.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,32 @@ export default class extends Controller {
8989

9090
disconnect() {
9191
this.stopMutationObserver();
92+
let currentSelectedValues: string[] = [];
93+
if (this.selectElement) {
94+
if (this.selectElement.multiple) {
95+
// For multiple selects, store the array of selected values
96+
currentSelectedValues = Array.from(this.selectElement.options)
97+
.filter((option) => option.selected)
98+
.map((option) => option.value);
99+
} else {
100+
// For single select, store the single value
101+
currentSelectedValues = [this.selectElement.value];
102+
}
103+
}
104+
105+
this.tomSelect.destroy();
106+
107+
if (this.selectElement) {
108+
if (this.selectElement.multiple) {
109+
// Restore selections for multiple selects
110+
Array.from(this.selectElement.options).forEach((option) => {
111+
option.selected = currentSelectedValues.includes(option.value);
112+
});
113+
} else {
114+
// Restore selection for single select
115+
this.selectElement.value = currentSelectedValues[0];
116+
}
117+
}
92118
}
93119

94120
#getCommonConfig(): Partial<TomSettings> {

src/Autocomplete/assets/test/controller.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,4 +726,53 @@ describe('AutocompleteController', () => {
726726
expect(fetchMock.requests()[0].url).toEqual('/path/to/autocomplete?query=');
727727
expect(fetchMock.requests()[1].url).toEqual('/path/to/autocomplete?query=foo');
728728
});
729+
730+
it('preserves the selected value and HTML with disconnect on single select', async () => {
731+
const { container, tomSelect } = await startAutocompleteTest(`
732+
<select data-testid="main-element" data-controller="autocomplete">
733+
<option value="">Select a dog</option>
734+
<option value="1">dog1</option>
735+
<option value="2">dog2</option>
736+
<option value="3">dog3</option>
737+
</select>
738+
`);
739+
740+
tomSelect.addItem('2');
741+
742+
const selectElement = getByTestId(container, 'main-element') as HTMLSelectElement;
743+
// trigger the disconnect
744+
selectElement.removeAttribute('data-controller');
745+
await waitFor(() => {
746+
expect(selectElement.className).not.toContain('tomselected');
747+
});
748+
expect(selectElement.value).toBe('2');
749+
});
750+
751+
it('preserves the selected value and HTML with disconnect on multiple select', async () => {
752+
const { container, tomSelect } = await startAutocompleteTest(`
753+
<select multiple data-testid="main-element" data-controller="autocomplete">
754+
<option value="">Select a dog</option>
755+
<option value="1">dog1</option>
756+
<option value="2">dog2</option>
757+
<option value="3">dog3</option>
758+
</select>
759+
`);
760+
761+
tomSelect.addItem('2');
762+
tomSelect.addItem('3');
763+
764+
const getSelectedValues = () => {
765+
return Array.from(selectElement.selectedOptions).map((option) => option.value).sort();
766+
}
767+
768+
const selectElement = getByTestId(container, 'main-element') as HTMLSelectElement;
769+
expect(getSelectedValues()).toEqual(['2', '3']);
770+
771+
// trigger the disconnect
772+
selectElement.removeAttribute('data-controller');
773+
await waitFor(() => {
774+
expect(selectElement.className).not.toContain('tomselected');
775+
});
776+
expect(getSelectedValues()).toEqual(['2', '3']);
777+
});
729778
});

0 commit comments

Comments
 (0)