Skip to content

Instantly share code, notes, and snippets.

@aalfiann
Last active January 29, 2024 05:40
Show Gist options
  • Save aalfiann/c03284330015ec7f3b5336a2c224a7a7 to your computer and use it in GitHub Desktop.
Save aalfiann/c03284330015ec7f3b5336a2c224a7a7 to your computer and use it in GitHub Desktop.
Select with checkbox pure javascript
"use strict";
/**
* Getmedik Select with Checkbox
*
* Note:
* Example required config
*
* {
* "element": "",
* "name": "",
* "placeholder": "-- Select --",
* "replaceholder": false,
* "data": [{"value": "", "text": "", "checked": false}]
* }
*/
class GMSelectBox {
constructor (option) {
this._show = true;
this.placeholder = '-- Select --';
this.replaceholder = false;
this.data = [];
if(typeof option === 'object' && option.constructor === Object){
for(var key in option) {
if(option.hasOwnProperty(key)) {
this[key] = option[key];
}
}
this._render();
document.addEventListener('click', this._clickHandler);
} else {
throw new Error('Option must be an object type!');
}
}
_render() {
var list = this.data;
var name = this.name;
var _listText = [];
for(var i=0; i<list.length; i++) {
if(list[i].checked) {
_listText.push(list[i].text);
}
}
if(this.replaceholder) {
if(_listText.length > 0) {
_listText = _listText.join(', ');
} else {
_listText = this.placeholder;
}
} else {
_listText = this.placeholder;
}
var dom = `<div id="section_${name}" class="gm-multipleSelection">
<div class="gm-selectBox ${name}_parent" id="select_${name}">
<select class="form-control">
<option id="${name}_select" data-replace="${this.replaceholder}" data-placeholder="${this.placeholder}">${_listText}</option>
</select>
<div class="gm-overSelect"></div>
</div>
<div class="gm-checkBoxes" id="${name}">
${list.map(function(item, index) {
return `<label class="${name}_label" for="${name}_item_${(index+1)}">
<input type="checkbox" id="${name}_item_${(index+1)}" name="${name}_item_${(index+1)}" value="${item.value}" ${(item.checked?'checked':'')}/>
<span class="gm-textBoxes">${item.text.substring(0, 34)}</span>
</label>`;
}).join('')}
</div>
</div>`;
document.getElementById(this.element).innerHTML = dom;
}
get(_parseInt) {
_parseInt = (_parseInt===undefined?false:_parseInt);
var result = [];
var labels = document.getElementById(this.name).getElementsByTagName('label');
for(var i=0; i<labels.length; i++) {
if(labels[i].getElementsByTagName('input')[0].checked === true) {
result.push(labels[i].getElementsByTagName('input')[0].value);
}
}
if(_parseInt) {
result = result.map(function (x) {
return parseInt(x, 10);
});
}
return result;
}
set(arr) {
var labels = document.getElementById(this.name).getElementsByTagName('label');
for(var i=0; i<labels.length; i++) {
for(var j=0; j<arr.length; j++) {
if(labels[i].getElementsByTagName('input')[0].value === arr[j].toString()) {
labels[i].getElementsByTagName('input')[0].checked = true;
}
}
}
// refresh
var selector = this.name+'_select';
if(document.getElementById(selector).getAttribute('data-replace') === 'true') {
var result = [];
for(var i=0; i<labels.length; i++) {
if(labels[i].getElementsByTagName('input')[0].checked === true) {
result.push(labels[i].getElementsByTagName('span')[0].textContent.substring(0, 34));
}
}
if(result.length > 0) {
result = result.join(', ');
} else {
result = document.getElementById(selector).getAttribute('data-placeholder');
}
document.getElementById(selector).innerHTML = result;
}
}
clear() {
var labels = document.getElementById(this.name).getElementsByTagName('label');
for(var i=0; i<labels.length; i++) {
labels[i].getElementsByTagName('input')[0].checked = false;
}
// refresh
var selector = this.name+'_select';
if(document.getElementById(selector).getAttribute('data-replace') === 'true') {
var result = document.getElementById(selector).getAttribute('data-placeholder');
document.getElementById(selector).innerHTML = result;
}
}
_clickHandler(event) {
if (event.target.parentNode.parentNode && event.target.parentNode.parentNode.children[1]) {
var name = event.target.parentNode.parentNode.children[1].id;
if(name) {
var checkboxes = document.getElementById(name);
if(this._show === undefined) {
this._show = true;
}
if(checkboxes) {
if (this._show) {
checkboxes.style.display = "block";
this._show = false;
} else {
checkboxes.style.display = "none";
this._show = true;
}
}
}
var itemCheck = event.target.parentNode.getAttribute('class');
if(itemCheck && itemCheck.indexOf('_label') !== -1) {
var selector = itemCheck.split('_')[0]+'_select';
if(event.target.value) {
var result = [];
var data = [];
var labels = document.getElementById(itemCheck.split('_')[0]).getElementsByTagName('label');
for(var i=0; i<labels.length; i++) {
if(labels[i].getElementsByTagName('input')[0].checked === true) {
result.push(labels[i].getElementsByTagName('span')[0].textContent.substring(0, 34));
data.push(labels[i].getElementsByTagName('input')[0].value);
}
}
const eventAwesome = new CustomEvent('gmselectbox:change', {
bubbles: true,
detail: {
name: itemCheck.split('_')[0],
data: data
}
});
event.target.dispatchEvent(eventAwesome);
if(document.getElementById(selector).getAttribute('data-replace') === 'true') {
if(result.length > 0) {
result = result.join(', ');
} else {
result = document.getElementById(selector).getAttribute('data-placeholder');
}
document.getElementById(selector).innerHTML = result;
}
}
}
}
}
}
document.head.innerHTML += `<style>
.gm-multipleSelection {
min-width: 150px;
max-width: 300px;
background-color: #FFF;
}
.gm-selectBox {
position: relative;
}
.gm-selectBox select {
width: 100%;
font-weight: bold;
}
.gm-overSelect {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
border: 1px #C0C8D7 solid;
border-radius: 5px 5px 5px 5px;
}
.gm-checkBoxes {
display: none;
border: 1px #C0C8D7 solid;
max-height: 200px;
overflow-y: auto;
background-color: white;
min-width: 150px;
max-width: 300px;
width: 100%;
position: relative;
z-index: 3;
}
.gm-checkBoxes label {
display: flex;
justify-content: flex-start;
align-items: center;
}
.gm-checkBoxes label:hover {
background-color: #EEFCFA;
}
.gm-checkBoxes label input[type="checkbox"]:checked {
background: #24B59D;
color: black;
}
.gm-checkBoxes label input[type="checkbox"] {
cursor: pointer;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
outline: 0;
background: white;
height: 16px;
width: 16px;
border: 1px solid #C0C8D7;
color: white;
}
.gm-checkBoxes label input[type="checkbox"]:after {
content: ' ';
position: relative;
left: 40%;
top: 20%;
width: 15%;
height: 40%;
border: solid #fff;
border-width: 0 2px 2px 0;
transform: rotate(50deg);
display: none;
}
.gm-checkBoxes label input[type="checkbox"]:checked:after {
display: block;
}
.gm-textBoxes {
position: relative;
font-family: 'Nunito Sans';
font-size: 14px;
font-weight: 400;
height: 100%;
display: block;
width: 100%;
padding: 10px 0px 10px 10px;
}
</style>`;
// =====================
// EXAMPLE HOW TO USE
// =====================
var gmselect = new GMSelectBox({
element: 'filter_test',
name: 'checkBoxes1',
placeholder: '-- Choose --',
replaceholder: true,
data: [
{
value: 1,
text: 'Tester 1'
},
{
value: 2,
text: 'Tester 2'
},
{
value: 3,
text: 'Tester 3'
},
{
value: 4,
text: 'Tester 4',
checked: true
},
{
value: 5,
text: 'Tester 5',
checked: true
}
]
});
var gmselect2 = new GMSelectBox({
element: 'filter_without_replaceholder',
name: 'checkBoxes2',
placeholder: '-- Choose --',
data: [
{
value: 7,
text: 'Tester 7'
},
{
value: 8,
text: 'Tester 8'
},
{
value: 9,
text: 'Tester 9'
},
{
value: 10,
text: 'Tester 10'
}
]
});
// LISTENER
document.addEventListener('gmselectbox:change', function (event) {
console.log(event.detail);
});
@aalfiann
Copy link
Author

aalfiann commented Jan 26, 2023

@pae0112
Copy link

pae0112 commented Jan 29, 2024

Got an issue!
If you click between text and right corner of select block, option will be marked as checked, but 'select' block closes
Screenshot_1

@pae0112
Copy link

pae0112 commented Jan 29, 2024

Fixed with this CSS

.gm-checkBoxes label {
    display: flex;
    justify-content: flex-start;
    align-items: center;
}
.gm-checkBoxes label input[type="checkbox"] {
    cursor: pointer;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    outline: 0;
    background: white;
    height: 16px;
    width: 16px;
    border: 1px solid #C0C8D7;
    color: white;
}
.gm-textBoxes {
    position: relative;
    font-family: 'Nunito Sans';
    font-size: 14px;
    font-weight: 400;
    height: 100%;
    display: block;
    width: 100%;
    padding: 10px 0px 10px 10px;
}

@aalfiann
Copy link
Author

Thanks @pae0112

Got it fixed.

Here is the new updated example >> https://jsfiddle.net/aalfiann/ufL1zbst/25/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment