1
+ /*
2
+ * Created by David Adams
3
+ * https://codeshack.io/dynamic-select-images-html-javascript/
4
+ *
5
+ * Released under the MIT license
6
+ */
7
+ class DynamicSelect {
8
+
9
+ constructor ( element , options = { } ) {
10
+ let defaults = {
11
+ placeholder : 'Select an option' ,
12
+ columns : 1 ,
13
+ name : '' ,
14
+ width : '' ,
15
+ height : '' ,
16
+ data : [ ] ,
17
+ onChange : function ( ) { }
18
+ } ;
19
+ this . options = Object . assign ( defaults , options ) ;
20
+ this . selectElement = typeof element === 'string' ? document . querySelector ( element ) : element ;
21
+ for ( const prop in this . selectElement . dataset ) {
22
+ if ( this . options [ prop ] !== undefined ) {
23
+ this . options [ prop ] = this . selectElement . dataset [ prop ] ;
24
+ }
25
+ }
26
+ this . name = this . selectElement . getAttribute ( 'name' ) ? this . selectElement . getAttribute ( 'name' ) : 'dynamic-select-' + Math . floor ( Math . random ( ) * 1000000 ) ;
27
+ if ( ! this . options . data . length ) {
28
+ let options = this . selectElement . querySelectorAll ( 'option' ) ;
29
+ for ( let i = 0 ; i < options . length ; i ++ ) {
30
+ this . options . data . push ( {
31
+ value : options [ i ] . value ,
32
+ text : options [ i ] . innerHTML ,
33
+ img : options [ i ] . getAttribute ( 'data-img' ) ,
34
+ selected : options [ i ] . selected ,
35
+ html : options [ i ] . getAttribute ( 'data-html' ) ,
36
+ imgWidth : options [ i ] . getAttribute ( 'data-img-width' ) ,
37
+ imgHeight : options [ i ] . getAttribute ( 'data-img-height' )
38
+ } ) ;
39
+ }
40
+ }
41
+ this . element = this . _template ( ) ;
42
+ this . selectElement . replaceWith ( this . element ) ;
43
+ this . _updateSelected ( ) ;
44
+ this . _eventHandlers ( ) ;
45
+ }
46
+
47
+ _template ( ) {
48
+ let optionsHTML = '' ;
49
+ for ( let i = 0 ; i < this . data . length ; i ++ ) {
50
+ let optionWidth = 100 / this . columns ;
51
+ let optionContent = '' ;
52
+ if ( this . data [ i ] . html ) {
53
+ optionContent = this . data [ i ] . html ;
54
+ } else {
55
+ optionContent = `
56
+ ${ this . data [ i ] . img ? `<img src="${ this . data [ i ] . img } " alt="${ this . data [ i ] . text } " class="${ this . data [ i ] . imgWidth && this . data [ i ] . imgHeight ? 'dynamic-size' : '' } " style="${ this . data [ i ] . imgWidth ? 'width:' + this . data [ i ] . imgWidth + ';' : '' } ${ this . data [ i ] . imgHeight ? 'height:' + this . data [ i ] . imgHeight + ';' : '' } ">` : '' }
57
+ ${ this . data [ i ] . text ? '<span class="dynamic-select-option-text">' + this . data [ i ] . text + '</span>' : '' }
58
+ ` ;
59
+ }
60
+ optionsHTML += `
61
+ <div class="dynamic-select-option${ this . data [ i ] . value == this . selectedValue ? ' dynamic-select-selected' : '' } ${ this . data [ i ] . text || this . data [ i ] . html ? '' : ' dynamic-select-no-text' } " data-value="${ this . data [ i ] . value } " style="width:${ optionWidth } %;${ this . height ? 'height:' + this . height + ';' : '' } ">
62
+ ${ optionContent }
63
+ </div>
64
+ ` ;
65
+ }
66
+ let template = `
67
+ <div class="dynamic-select ${ this . name } "${ this . selectElement . id ? ' id="' + this . selectElement . id + '"' : '' } style="${ this . width ? 'width:' + this . width + ';' : '' } ${ this . height ? 'height:' + this . height + ';' : '' } ">
68
+ <input type="hidden" name="${ this . name } " value="${ this . selectedValue } ">
69
+ <div class="dynamic-select-header" style="${ this . width ? 'width:' + this . width + ';' : '' } ${ this . height ? 'height:' + this . height + ';' : '' } "><span class="dynamic-select-header-placeholder">${ this . placeholder } </span></div>
70
+ <div class="dynamic-select-options" style="${ this . options . dropdownWidth ? 'width:' + this . options . dropdownWidth + ';' : '' } ${ this . options . dropdownHeight ? 'height:' + this . options . dropdownHeight + ';' : '' } ">${ optionsHTML } </div>
71
+ </div>
72
+ ` ;
73
+ let element = document . createElement ( 'div' ) ;
74
+ element . innerHTML = template ;
75
+ return element ;
76
+ }
77
+
78
+ _eventHandlers ( ) {
79
+ this . element . querySelectorAll ( '.dynamic-select-option' ) . forEach ( option => {
80
+ option . onclick = ( ) => {
81
+ this . element . querySelectorAll ( '.dynamic-select-selected' ) . forEach ( selected => selected . classList . remove ( 'dynamic-select-selected' ) ) ;
82
+ option . classList . add ( 'dynamic-select-selected' ) ;
83
+ this . element . querySelector ( '.dynamic-select-header' ) . innerHTML = option . innerHTML ;
84
+ this . element . querySelector ( 'input' ) . value = option . getAttribute ( 'data-value' ) ;
85
+ this . data . forEach ( data => data . selected = false ) ;
86
+ this . data . filter ( data => data . value == option . getAttribute ( 'data-value' ) ) [ 0 ] . selected = true ;
87
+ this . element . querySelector ( '.dynamic-select-header' ) . classList . remove ( 'dynamic-select-header-active' ) ;
88
+ this . options . onChange ( option . getAttribute ( 'data-value' ) , option . querySelector ( '.dynamic-select-option-text' ) ? option . querySelector ( '.dynamic-select-option-text' ) . innerHTML : '' , option ) ;
89
+ } ;
90
+ } ) ;
91
+ this . element . querySelector ( '.dynamic-select-header' ) . onclick = ( ) => {
92
+ this . element . querySelector ( '.dynamic-select-header' ) . classList . toggle ( 'dynamic-select-header-active' ) ;
93
+ } ;
94
+ if ( this . selectElement . id && document . querySelector ( 'label[for="' + this . selectElement . id + '"]' ) ) {
95
+ document . querySelector ( 'label[for="' + this . selectElement . id + '"]' ) . onclick = ( ) => {
96
+ this . element . querySelector ( '.dynamic-select-header' ) . classList . toggle ( 'dynamic-select-header-active' ) ;
97
+ } ;
98
+ }
99
+ document . addEventListener ( 'click' , event => {
100
+ if ( ! event . target . closest ( '.' + this . name ) && ! event . target . closest ( 'label[for="' + this . selectElement . id + '"]' ) ) {
101
+ this . element . querySelector ( '.dynamic-select-header' ) . classList . remove ( 'dynamic-select-header-active' ) ;
102
+ }
103
+ } ) ;
104
+ }
105
+
106
+ _updateSelected ( ) {
107
+ if ( this . selectedValue ) {
108
+ this . element . querySelector ( '.dynamic-select-header' ) . innerHTML = this . element . querySelector ( '.dynamic-select-selected' ) . innerHTML ;
109
+ }
110
+ }
111
+
112
+ get selectedValue ( ) {
113
+ let selected = this . data . filter ( option => option . selected ) ;
114
+ selected = selected . length ? selected [ 0 ] . value : '' ;
115
+ return selected ;
116
+ }
117
+
118
+ set data ( value ) {
119
+ this . options . data = value ;
120
+ }
121
+
122
+ get data ( ) {
123
+ return this . options . data ;
124
+ }
125
+
126
+ set selectElement ( value ) {
127
+ this . options . selectElement = value ;
128
+ }
129
+
130
+ get selectElement ( ) {
131
+ return this . options . selectElement ;
132
+ }
133
+
134
+ set element ( value ) {
135
+ this . options . element = value ;
136
+ }
137
+
138
+ get element ( ) {
139
+ return this . options . element ;
140
+ }
141
+
142
+ set placeholder ( value ) {
143
+ this . options . placeholder = value ;
144
+ }
145
+
146
+ get placeholder ( ) {
147
+ return this . options . placeholder ;
148
+ }
149
+
150
+ set columns ( value ) {
151
+ this . options . columns = value ;
152
+ }
153
+
154
+ get columns ( ) {
155
+ return this . options . columns ;
156
+ }
157
+
158
+ set name ( value ) {
159
+ this . options . name = value ;
160
+ }
161
+
162
+ get name ( ) {
163
+ return this . options . name ;
164
+ }
165
+
166
+ set width ( value ) {
167
+ this . options . width = value ;
168
+ }
169
+
170
+ get width ( ) {
171
+ return this . options . width ;
172
+ }
173
+
174
+ set height ( value ) {
175
+ this . options . height = value ;
176
+ }
177
+
178
+ get height ( ) {
179
+ return this . options . height ;
180
+ }
181
+
182
+ }
183
+ document . querySelectorAll ( '[data-dynamic-select]' ) . forEach ( select => new DynamicSelect ( select ) ) ;
0 commit comments