Skip to content

Commit a468422

Browse files
authored
Add files via upload
1 parent ecb2e6a commit a468422

File tree

4 files changed

+543
-0
lines changed

4 files changed

+543
-0
lines changed

DynamicSelect.css

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
.dynamic-select {
2+
display: flex;
3+
box-sizing: border-box;
4+
flex-direction: column;
5+
position: relative;
6+
width: 100%;
7+
user-select: none;
8+
}
9+
.dynamic-select .dynamic-select-header {
10+
border: 1px solid #dee2e6;
11+
padding: 7px 30px 7px 12px;
12+
}
13+
.dynamic-select .dynamic-select-header::after {
14+
content: "";
15+
display: block;
16+
position: absolute;
17+
top: 50%;
18+
right: 15px;
19+
transform: translateY(-50%);
20+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23949ba3' viewBox='0 0 16 16'%3E%3Cpath d='M8 13.1l-8-8 2.1-2.2 5.9 5.9 5.9-5.9 2.1 2.2z'/%3E%3C/svg%3E");
21+
height: 12px;
22+
width: 12px;
23+
}
24+
.dynamic-select .dynamic-select-header.dynamic-select-header-active {
25+
border-color: #c1c9d0;
26+
}
27+
.dynamic-select .dynamic-select-header.dynamic-select-header-active::after {
28+
transform: translateY(-50%) rotate(180deg);
29+
}
30+
.dynamic-select .dynamic-select-header.dynamic-select-header-active + .dynamic-select-options {
31+
display: flex;
32+
}
33+
.dynamic-select .dynamic-select-header .dynamic-select-header-placeholder {
34+
color: #65727e;
35+
}
36+
.dynamic-select .dynamic-select-options {
37+
display: none;
38+
box-sizing: border-box;
39+
flex-flow: wrap;
40+
position: absolute;
41+
top: 100%;
42+
left: 0;
43+
right: 0;
44+
z-index: 999;
45+
margin-top: 5px;
46+
padding: 5px;
47+
background-color: #fff;
48+
border-radius: 5px;
49+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
50+
max-height: 200px;
51+
overflow-y: auto;
52+
overflow-x: hidden;
53+
}
54+
.dynamic-select .dynamic-select-options::-webkit-scrollbar {
55+
width: 5px;
56+
}
57+
.dynamic-select .dynamic-select-options::-webkit-scrollbar-track {
58+
background: #f0f1f3;
59+
}
60+
.dynamic-select .dynamic-select-options::-webkit-scrollbar-thumb {
61+
background: #cdcfd1;
62+
}
63+
.dynamic-select .dynamic-select-options::-webkit-scrollbar-thumb:hover {
64+
background: #b2b6b9;
65+
}
66+
.dynamic-select .dynamic-select-options .dynamic-select-option {
67+
padding: 7px 12px;
68+
}
69+
.dynamic-select .dynamic-select-options .dynamic-select-option:hover, .dynamic-select .dynamic-select-options .dynamic-select-option:active {
70+
background-color: #f3f4f7;
71+
}
72+
.dynamic-select .dynamic-select-header, .dynamic-select .dynamic-select-option {
73+
display: flex;
74+
box-sizing: border-box;
75+
align-items: center;
76+
border-radius: 5px;
77+
cursor: pointer;
78+
display: flex;
79+
align-items: center;
80+
width: 100%;
81+
height: 45px;
82+
font-size: 16px;
83+
color: #212529;
84+
}
85+
.dynamic-select .dynamic-select-header img, .dynamic-select .dynamic-select-option img {
86+
object-fit: contain;
87+
max-height: 100%;
88+
max-width: 100%;
89+
}
90+
.dynamic-select .dynamic-select-header img.dynamic-size, .dynamic-select .dynamic-select-option img.dynamic-size {
91+
object-fit: fill;
92+
max-height: none;
93+
max-width: none;
94+
}
95+
.dynamic-select .dynamic-select-header img, .dynamic-select .dynamic-select-header svg, .dynamic-select .dynamic-select-header i, .dynamic-select .dynamic-select-header span, .dynamic-select .dynamic-select-option img, .dynamic-select .dynamic-select-option svg, .dynamic-select .dynamic-select-option i, .dynamic-select .dynamic-select-option span {
96+
box-sizing: border-box;
97+
margin-right: 10px;
98+
}
99+
.dynamic-select .dynamic-select-header.dynamic-select-no-text, .dynamic-select .dynamic-select-option.dynamic-select-no-text {
100+
justify-content: center;
101+
}
102+
.dynamic-select .dynamic-select-header.dynamic-select-no-text img, .dynamic-select .dynamic-select-header.dynamic-select-no-text svg, .dynamic-select .dynamic-select-header.dynamic-select-no-text i, .dynamic-select .dynamic-select-header.dynamic-select-no-text span, .dynamic-select .dynamic-select-option.dynamic-select-no-text img, .dynamic-select .dynamic-select-option.dynamic-select-no-text svg, .dynamic-select .dynamic-select-option.dynamic-select-no-text i, .dynamic-select .dynamic-select-option.dynamic-select-no-text span {
103+
margin-right: 0;
104+
}
105+
.dynamic-select .dynamic-select-header .dynamic-select-option-text, .dynamic-select .dynamic-select-option .dynamic-select-option-text {
106+
box-sizing: border-box;
107+
flex: 1;
108+
overflow: hidden;
109+
text-overflow: ellipsis;
110+
white-space: nowrap;
111+
color: inherit;
112+
font-size: inherit;
113+
}

DynamicSelect.js

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
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

Comments
 (0)