@@ -17,6 +17,10 @@ export interface AutocompleteConnectOptions {
17
17
tomSelect : TomSelect ;
18
18
options : any ;
19
19
}
20
+ interface OptionDataStructure {
21
+ value : string ;
22
+ text : string ;
23
+ }
20
24
21
25
export default class extends Controller {
22
26
static values = {
@@ -47,7 +51,7 @@ export default class extends Controller {
47
51
private mutationObserver : MutationObserver ;
48
52
private isObserving = false ;
49
53
private hasLoadedChoicesPreviously = false ;
50
- private originalOptions : Array < { value : string ; text : string ; group : string | null } > = [ ] ;
54
+ private originalOptions : Array < OptionDataStructure > = [ ] ;
51
55
52
56
initialize ( ) {
53
57
if ( ! this . mutationObserver ) {
@@ -158,6 +162,47 @@ export default class extends Controller {
158
162
this . tomSelect . setTextboxValue ( '' ) ;
159
163
} ,
160
164
closeAfterSelect : true ,
165
+ // fix positioning (in the dropdown) of options added through addOption()
166
+ onOptionAdd : ( value : string , data : { [ key : string ] : any } ) => {
167
+ let parentElement = this . tomSelect . input as Element ;
168
+ let optgroupData = null ;
169
+
170
+ const optgroup = data [ this . tomSelect . settings . optgroupField ] ;
171
+ if ( optgroup && this . tomSelect . optgroups ) {
172
+ optgroupData = this . tomSelect . optgroups [ optgroup ] ;
173
+ if ( optgroupData ) {
174
+ const optgroupElement = parentElement . querySelector ( `optgroup[label="${ optgroupData . label } "]` ) ;
175
+ if ( optgroupElement ) {
176
+ parentElement = optgroupElement ;
177
+ }
178
+ }
179
+ }
180
+
181
+ const optionElement = document . createElement ( 'option' ) ;
182
+ optionElement . value = value ;
183
+ optionElement . text = data [ this . tomSelect . settings . labelField ] ;
184
+
185
+ const optionOrder = data [ '$order' ] ;
186
+ let orderedOption = null ;
187
+
188
+ for ( const [ , tomSelectOption ] of Object . entries ( this . tomSelect . options ) ) {
189
+ if ( tomSelectOption [ '$order' ] === optionOrder ) {
190
+ orderedOption = parentElement . querySelector (
191
+ `:scope > option[value="${ tomSelectOption [ this . tomSelect . settings . valueField ] } "]`
192
+ ) ;
193
+
194
+ break ;
195
+ }
196
+ }
197
+
198
+ if ( orderedOption ) {
199
+ orderedOption . insertAdjacentElement ( 'afterend' , optionElement ) ;
200
+ } else if ( optionOrder >= 0 ) {
201
+ parentElement . append ( optionElement ) ;
202
+ } else {
203
+ parentElement . prepend ( optionElement ) ;
204
+ }
205
+ } ,
161
206
} ;
162
207
163
208
// for non-autocompleting input elements, avoid the "No results" message that always shows
@@ -414,20 +459,16 @@ export default class extends Controller {
414
459
}
415
460
}
416
461
417
- private createOptionsDataStructure (
418
- selectElement : HTMLSelectElement
419
- ) : Array < { value : string ; text : string ; group : string | null } > {
462
+ private createOptionsDataStructure ( selectElement : HTMLSelectElement ) : Array < OptionDataStructure > {
420
463
return Array . from ( selectElement . options ) . map ( ( option ) => {
421
- const optgroup = option . closest ( 'optgroup' ) ;
422
464
return {
423
465
value : option . value ,
424
466
text : option . text ,
425
- group : optgroup ? optgroup . label : null ,
426
467
} ;
427
468
} ) ;
428
469
}
429
470
430
- private areOptionsEquivalent ( newOptions : Array < { value : string ; text : string ; group : string | null } > ) : boolean {
471
+ private areOptionsEquivalent ( newOptions : Array < OptionDataStructure > ) : boolean {
431
472
// remove the empty option, which is added by TomSelect so may be missing from new options
432
473
const filteredOriginalOptions = this . originalOptions . filter ( ( option ) => option . value !== '' ) ;
433
474
const filteredNewOptions = newOptions . filter ( ( option ) => option . value !== '' ) ;
@@ -447,8 +488,7 @@ export default class extends Controller {
447
488
return false ;
448
489
}
449
490
450
- const normalizeOption = ( option : { value : string ; text : string ; group : string | null } ) =>
451
- `${ option . value } -${ option . text } -${ option . group } ` ;
491
+ const normalizeOption = ( option : OptionDataStructure ) => `${ option . value } -${ option . text } ` ;
452
492
const originalOptionsSet = new Set ( filteredOriginalOptions . map ( normalizeOption ) ) ;
453
493
const newOptionsSet = new Set ( filteredNewOptions . map ( normalizeOption ) ) ;
454
494
0 commit comments