1

What would be the best way to turn a json object into a sorted HTML select (straight javascript only)?

The format of the json can change if needed. I have been searching and most documentation says that object keys can not be sorted only arrays can be sorted, but I couldn't figure out how I would modify the structure of the json to make it an array and therefore easily sortable.

var json = {
                "group3": [
                  {"value33": "label33"},
                  {"value13": "label13"},
                  {"value23": "label23"}
                ],
                "group1": [
                  {"value21": "label21"},
                  {"value31": "label31"},
                  {"value11": "label11"}
                ],
                "group2": [
                  {"value22": "label22"},
                  {"value12": "label12"},
                  {"value32": "label32"}
                ]
              };

Will become this:

    <select multiple="multiple">
      <optgroup label="Group 1">
        <option value="value11">Label 11</option>
        <option value="value21">Label 21</option>
        <option value="value31">Label 31</option>
      </optgroup>
      <optgroup label="Group 2">
        <option value="value12">Label 12</option>
        <option value="value22">Label 22</option>
        <option value="value32">Label 32</option>
      </optgroup>
      <optgroup label="Group 3">
        <option value="value13">Label 13</option>
        <option value="value23">Label 23</option>
        <option value="value33">Label 33</option>
      </optgroup>
    </select>
2
  • 3
    Have you tried anything? Please post your attempt to solve the problem. Commented Aug 21, 2014 at 16:59
  • 1
    Create an (empty) array. Split the number off the end of the key (group?) and use that for the array index. Fill the array. Then, loop through the array using a for loop and write the data out. Commented Aug 21, 2014 at 17:01

3 Answers 3

1

I was able to solve this by modifying the structure of your JSON slightly (since you said this was OK) and writing a custom sorting function.

Fiddle here: http://jsfiddle.net/9urusm5p/2/

<html>
    <head>
        <script>

            //take an object and loop through all the properties
            //each property goes into an array and is sorted
            //loop through the sorted array and build an output array of objects
            //objects in output have 2 properties
            //key = original property name, value = original property value
            function createSortedArray(obj) {
                var returnArray = [];
                var sortingArray = [];
                for(var property in obj) {
                    sortingArray.push(property);
                }
                sortingArray.sort();
                for(var index = 0; index < sortingArray.length; index++) {
                    var property = sortingArray[index];
                    var newObject = {};
                    newObject.key = property;
                    newObject.value = obj[property];
                    returnArray.push(newObject);
                }
                return returnArray;
            }

            window.onload = function() {
                var json = {
                                "group3": {
                                  "value33": "label33",
                                  "value13": "label13",
                                  "value23": "label23"
                                },
                                "group1": {
                                  "value21": "label21",
                                  "value31": "label31",
                                  "value11": "label11"
                                },
                                "group2": {
                                  "value22": "label22",
                                  "value12": "label12",
                                  "value32": "label32"
                                }
                              };

                //sort source object with function above and loop through results
                var sortedGroups = createSortedArray(json);
                for(var index = 0; index < sortedGroups.length; index++) {
                    var group = sortedGroups[index];

                    //create optgroup tag and assign label property
                    var optGroup = document.createElement("optgroup");
                    optGroup.label = group.key;

                    //sort the properties of the current group using our function again
                    var optionArray = createSortedArray(group.value);
                    for(var optionIndex = 0; optionIndex <  optionArray.length; optionIndex++ ) {
                        //options are now sorted, just add to the optgroup
                        var option = optionArray[optionIndex];
                        var opt = document.createElement("option");
                        opt.value = option.key;
                        opt.textContent  = option.value;
                        optGroup.appendChild(opt);
                    }

                    //add optgroup to select tag
                    document.getElementById("select").appendChild(optGroup);
                }
            }
        </script>
    </head>
    <body>
        <select id="select" multiple="multiple" style="height:300px;width:100px;"></select>
    </body>
</html>
Sign up to request clarification or add additional context in comments.

3 Comments

When I see something like this, JS just becomes a blur. This is definitely the work of magic. Thank you. If you have an online tip jar somewhere let me know.
P.S. I modified it so that it could handle a json of select options with no optgroup. Let me know if this good way to go about it. jsfiddle.net/djlerman/gah4uxde
Looks good to me. I also added some comments above that will hopefully help you understand the code better.
0

Dictionaries in JavaScript can't be sorted because they have no concept of order at all. The way I usually solve this is something along the lines of:

var json = [
  {
    "name": "group1",
    "content": [
      {"value": "value13", "label": "label13"},
      {"value": "value11", "label": "label33"},
      ...
    ],
  },
  {
    "name": "group2",
    "content": [
      ...
    ]
  },
  ...
}

To sort an object like this, you can use a custom sorting function. To sort each group into order:

json.sort(function(a, b) {
  if (a.name < b.name) {
    return -1;
  } else if (a.name > b.name) {
    return 1;
  } else {
    return 0;
  }
}

To sort each content array inside a group you can just loop over each value in the json array, and call sort on its content using another custom sorting function like above. For more info on these: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

1 Comment

Wow this is pretty simple. How could the Options be sorted by label? It doesn't work if I change the contents of the sort to a.content.label < b.content.label
0

By using document.createElement, and a few for loops, we can accomplish this: http://jsfiddle.net/kruduuzo/

First we use a for in loop to get the names of the keys to use as the optgroup. Then we loop through the array within that optgroup, using the group name that we just discovered. Once inside, you then do another for in loop to get the value name, and then use it to set the textContent. Then you simply append the children to their respective parents, and finally the select to the body.

var body = document.getElementsByTagName("body")[0];

var select = document.createElement("select");
select.multiple = true;

for (group in json) {
    var optgroup = document.createElement("optgroup");
    optgroup.label = group;
    var i = 0, count = json[group].length;
    for (i; i < count; i++) {
        var opt = document.createElement("option");
        for (value in json[group][i]) {
            opt.value = value;
            opt.textContent = json[group][i][value];
        }
        optgroup.appendChild(opt);
    }
    select.appendChild(optgroup);
}

body.appendChild(select);

I didn't notice that you said that the format of the json could change. In that case, I'd do something similar to what GravityScore did to your json. However, if you find it easier to keep your json in the same format, my solution definitely gets you where you need to be.

3 Comments

This is perfect, straight forward and understandable for creating the Select. How would it modified to handle the sorting?
@DonavonLerman Good question... I admit that I only just noticed that you also wanted it to sort. I think I jumped the gun on this. As GravityScore says, you cannot sort it in your current format. You'd have to rearrange it.
Do you have a suggestion? I tried: `var json = { [ { "group3": [ {"value33": "label33"}, {"value13": "label13"}, {"value23": "label23"} ] } ], [ { "group1": [ {"value21": "label21"}, {"value31": "label31"}, {"value11": "label11"} ] } ] };

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.