This function converts a regular <select>
element both into an intented ul
/li
structure and JSON. It’s light and it’s been developed for a specific internal purpose. If you find it useful, with a small change, it also allows for exporting the option state (selected or not).
Features
onclick
convert select to indentedul
/li
includingoptgroup
elementsonclick
JSONify<select>
toconsole.log()
and it can further be passed to aFetch
event
Demo
See a live demo here.
HTML
The HTML structure builds a multiselect dropdown and an empty JSON container:
<div id="myselect">
<select id="multiselect" name="languages[]" size="6" multiple>
<optgroup label="More Cars">
<option value="1">JavaScript</option>
<option value="2">CSS</option>
<option value="3">Script</option>
<option value="4">Ruby</option>
<option value="5">Go</option>
<option value="6">PHP</option>
<option value="7">.Com</option>
<option value="8">Java</option>
</optgroup>
<optgroup label="Swedish Cars">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
</optgroup>
<optgroup label="German Cars">
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</optgroup>
</select>
<div id="json"></div>
</div>
JavaScript
<script>
function jsonifySelect(selectId) {
const theSelect = document.getElementById('multiselect'),
optgroups = theSelect.getElementsByTagName('optgroup');
let myObj = {};
for (let i = 0; i < optgroups.length; i++) {
myObj[optgroups[i].getAttribute('label')] = [];
let options = optgroups[i].getElementsByTagName('option');
for (let j = 0; j < options.length; j++) {
myObj[optgroups[i].getAttribute('label')].push(options[j].innerHTML);
}
}
return myObj;
}
function recurse(data) {
let result = '<ul>';
for (let key in data) {
if (typeof(data[key]) == 'object' && data[key] != null) {
let x = key*1;
if (isNaN(x)) {
result += `<li>${key}<ul>`;
}
result += recurse(data[key]);
result += '</ul></li>';
} else {
result += (`<li data-value="${data[key]}">${data[key]}</li>'`);
}
}
result += '</ul>';
return result;
}
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('myselect').addEventListener('click', () => {
console.log(jsonifySelect('multiselect'));
let htmlStr = recurse(jsonifySelect('multiselect'));
document.getElementById('json').innerHTML = htmlStr;
});
});
</script>
Note: In the jsonifySelect()
function, inside the for (let j = 0; j < options.length; j++) {
loop, check for options[j].selected
to see if the option has been selected by the user.
Example:
<script>
// code here
for (let j = 0; j < options.length; j++) {
myObj[optgroups[i].getAttribute('label')].push([options[j].innerHTML, options[j].selected]);
}
// more code here
</script>
In this case, I push an array containing the name of the item and the option state (boolean), true
or false
. This requires some changes to the ul
/li
structure, but if you’re not using and you’re only the JSON result, you should be good.