Skip to content

Commit 0bc7394

Browse files
committed
Support duplicate options
Now that the data objects have the `element` property, we can test to make sure it's a DOM element and then use it for selecting the option. This allows us to select multiple options with the same id, as well as handle cases where that is already happening. You cannot use `$e.val()` to select two options with the same id, as jQuery will reject it, but you can set the second option to `.selected = true`, which is supported.
1 parent fe13608 commit 0bc7394

9 files changed

Lines changed: 281 additions & 3 deletions

File tree

dist/js/select2.amd.full.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2153,6 +2153,15 @@ define('select2/data/select',[
21532153
SelectAdapter.prototype.select = function (data) {
21542154
var self = this;
21552155

2156+
// If data.element is a DOM nose, use it instead
2157+
if ($(data.element).is('option')) {
2158+
data.element.selected = true;
2159+
2160+
this.$element.trigger('change');
2161+
2162+
return;
2163+
}
2164+
21562165
if (this.$element.prop('multiple')) {
21572166
this.current(function (currentData) {
21582167
var val = [];
@@ -2187,6 +2196,14 @@ define('select2/data/select',[
21872196
return;
21882197
}
21892198

2199+
if ($(data.element).is('option')) {
2200+
data.element.selected = false;
2201+
2202+
this.$element.trigger('change');
2203+
2204+
return;
2205+
}
2206+
21902207
this.current(function (currentData) {
21912208
var val = [];
21922209

dist/js/select2.amd.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2153,6 +2153,15 @@ define('select2/data/select',[
21532153
SelectAdapter.prototype.select = function (data) {
21542154
var self = this;
21552155

2156+
// If data.element is a DOM nose, use it instead
2157+
if ($(data.element).is('option')) {
2158+
data.element.selected = true;
2159+
2160+
this.$element.trigger('change');
2161+
2162+
return;
2163+
}
2164+
21562165
if (this.$element.prop('multiple')) {
21572166
this.current(function (currentData) {
21582167
var val = [];
@@ -2187,6 +2196,14 @@ define('select2/data/select',[
21872196
return;
21882197
}
21892198

2199+
if ($(data.element).is('option')) {
2200+
data.element.selected = false;
2201+
2202+
this.$element.trigger('change');
2203+
2204+
return;
2205+
}
2206+
21902207
this.current(function (currentData) {
21912208
var val = [];
21922209

dist/js/select2.full.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11688,6 +11688,15 @@ define('select2/data/select',[
1168811688
SelectAdapter.prototype.select = function (data) {
1168911689
var self = this;
1169011690

11691+
// If data.element is a DOM nose, use it instead
11692+
if ($(data.element).is('option')) {
11693+
data.element.selected = true;
11694+
11695+
this.$element.trigger('change');
11696+
11697+
return;
11698+
}
11699+
1169111700
if (this.$element.prop('multiple')) {
1169211701
this.current(function (currentData) {
1169311702
var val = [];
@@ -11722,6 +11731,14 @@ define('select2/data/select',[
1172211731
return;
1172311732
}
1172411733

11734+
if ($(data.element).is('option')) {
11735+
data.element.selected = false;
11736+
11737+
this.$element.trigger('change');
11738+
11739+
return;
11740+
}
11741+
1172511742
this.current(function (currentData) {
1172611743
var val = [];
1172711744

dist/js/select2.full.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/js/select2.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2581,6 +2581,15 @@ define('select2/data/select',[
25812581
SelectAdapter.prototype.select = function (data) {
25822582
var self = this;
25832583

2584+
// If data.element is a DOM nose, use it instead
2585+
if ($(data.element).is('option')) {
2586+
data.element.selected = true;
2587+
2588+
this.$element.trigger('change');
2589+
2590+
return;
2591+
}
2592+
25842593
if (this.$element.prop('multiple')) {
25852594
this.current(function (currentData) {
25862595
var val = [];
@@ -2615,6 +2624,14 @@ define('select2/data/select',[
26152624
return;
26162625
}
26172626

2627+
if ($(data.element).is('option')) {
2628+
data.element.selected = false;
2629+
2630+
this.$element.trigger('change');
2631+
2632+
return;
2633+
}
2634+
26182635
this.current(function (currentData) {
26192636
var val = [];
26202637

dist/js/select2.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/js/select2/data/select.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ define([
3030
SelectAdapter.prototype.select = function (data) {
3131
var self = this;
3232

33+
// If data.element is a DOM nose, use it instead
34+
if ($(data.element).is('option')) {
35+
data.element.selected = true;
36+
37+
this.$element.trigger('change');
38+
39+
return;
40+
}
41+
3342
if (this.$element.prop('multiple')) {
3443
this.current(function (currentData) {
3544
var val = [];
@@ -64,6 +73,14 @@ define([
6473
return;
6574
}
6675

76+
if ($(data.element).is('option')) {
77+
data.element.selected = false;
78+
79+
this.$element.trigger('change');
80+
81+
return;
82+
}
83+
6784
this.current(function (currentData) {
6885
var val = [];
6986

tests/data/select-tests.js

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,158 @@ test('multiple adds to the old value', function (assert) {
154154
assert.deepEqual($select.val(), ['default', '2']);
155155
});
156156

157+
test('duplicates - single - same id on select triggers change',
158+
function (assert) {
159+
var $select = $('#qunit-fixture .duplicates');
160+
161+
var data = new SelectData($select, data);
162+
var second = $('#qunit-fixture .duplicates option')[2];
163+
164+
var changeTriggered = false;
165+
166+
assert.equal($select.val(), 'one');
167+
168+
$select.on('change', function () {
169+
changeTriggered = true;
170+
});
171+
172+
data.select({
173+
id: 'one',
174+
text: 'Uno',
175+
element: second
176+
});
177+
178+
assert.equal(
179+
$select.val(),
180+
'one',
181+
'The value never changed'
182+
);
183+
184+
assert.ok(
185+
changeTriggered,
186+
'The change event should be triggered'
187+
);
188+
189+
assert.ok(
190+
second.selected,
191+
'The second duplicate is selected, not the first'
192+
);
193+
});
194+
195+
test('duplicates - single - different id on select triggers change',
196+
function (assert) {
197+
var $select = $('#qunit-fixture .duplicates');
198+
199+
var data = new SelectData($select, data);
200+
var second = $('#qunit-fixture .duplicates option')[2];
201+
202+
var changeTriggered = false;
203+
204+
$select.val('two');
205+
206+
$select.on('change', function () {
207+
changeTriggered = true;
208+
});
209+
210+
data.select({
211+
id: 'one',
212+
text: 'Uno',
213+
element: second
214+
});
215+
216+
assert.equal(
217+
$select.val(),
218+
'one',
219+
'The value changed to the duplicate id'
220+
);
221+
222+
assert.ok(
223+
changeTriggered,
224+
'The change event should be triggered'
225+
);
226+
227+
assert.ok(
228+
second.selected,
229+
'The second duplicate is selected, not the first'
230+
);
231+
});
232+
233+
test('duplicates - multiple - same id on select triggers change',
234+
function (assert) {
235+
var $select = $('#qunit-fixture .duplicates-multi');
236+
237+
var data = new SelectData($select, data);
238+
var second = $('#qunit-fixture .duplicates-multi option')[2];
239+
240+
var changeTriggered = false;
241+
242+
$select.val(['one']);
243+
244+
$select.on('change', function () {
245+
changeTriggered = true;
246+
});
247+
248+
data.select({
249+
id: 'one',
250+
text: 'Uno',
251+
element: second
252+
});
253+
254+
assert.deepEqual(
255+
$select.val(),
256+
['one', 'one'],
257+
'The value now has duplicates'
258+
);
259+
260+
assert.ok(
261+
changeTriggered,
262+
'The change event should be triggered'
263+
);
264+
265+
assert.ok(
266+
second.selected,
267+
'The second duplicate is selected, not the first'
268+
);
269+
});
270+
271+
test('duplicates - multiple - different id on select triggers change',
272+
function (assert) {
273+
var $select = $('#qunit-fixture .duplicates-multi');
274+
275+
var data = new SelectData($select, data);
276+
var second = $('#qunit-fixture .duplicates-multi option')[2];
277+
278+
var changeTriggered = false;
279+
280+
$select.val(['two']);
281+
282+
$select.on('change', function () {
283+
changeTriggered = true;
284+
});
285+
286+
data.select({
287+
id: 'one',
288+
text: 'Uno',
289+
element: second
290+
});
291+
292+
assert.deepEqual(
293+
$select.val(),
294+
['two', 'one'],
295+
'The value has the new id'
296+
);
297+
298+
assert.ok(
299+
changeTriggered,
300+
'The change event should be triggered'
301+
);
302+
303+
assert.ok(
304+
second.selected,
305+
'The second duplicate is selected, not the first'
306+
);
307+
});
308+
157309
module('Data adapter - Select - query');
158310

159311
test('all options are returned with no term', function (assert) {
@@ -258,3 +410,32 @@ test('empty optgroups are still shown when queried', function (assert) {
258410
);
259411
});
260412
});
413+
414+
test('multiple options with the same value are returned', function (assert) {
415+
var $select = $('#qunit-fixture .duplicates');
416+
417+
var data = new SelectData($select, options);
418+
419+
data.query({}, function (data) {
420+
assert.equal(
421+
data.length,
422+
3,
423+
'The duplicate option should still be returned when queried'
424+
);
425+
426+
var first = data[0];
427+
var duplicate = data[2];
428+
429+
assert.equal(
430+
first.id,
431+
duplicate.id,
432+
'The duplicates should have the same id'
433+
);
434+
435+
assert.notEqual(
436+
first.text,
437+
duplicate.text,
438+
'The duplicates do not have the same text'
439+
);
440+
});
441+
});

tests/data/select.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@
2626
</optgroup>
2727
<optgroup label="Empty"></optgroup>
2828
</select>
29+
30+
<select class="duplicates">
31+
<option value="one">One</option>
32+
<option value="two">Two</option>
33+
<option value="one">Uno</option>
34+
</select>
35+
36+
<select class="duplicates-multi" multiple="multiple">
37+
<option value="one">One</option>
38+
<option value="two">Two</option>
39+
<option value="one">Uno</option>
40+
</select>
2941
</div>
3042

3143
<script src="../vendor/qunit-1.14.0.js" type="text/javascript"></script>

0 commit comments

Comments
 (0)