GroupBy in JavaScript to group JSON data and populate on optgroup

20,286

Solution 1

If I were you, I would use a small library called Underscore to group the data which is returned in a easier representation.

See this code below and you may also see this live demo:

var groupData = _.groupBy(data, function (obj) {
    return obj.category;
});

var optGroups = [];
for (var key in groupData) {
    if (groupData.hasOwnProperty(key)) {
        var optGroup = $("<optgroup></optgroup>");
        optGroup.attr("label", key);
        var currentGroup = groupData[key];
        for (var i = 0; i < currentGroup.length; i++) {
            $("<option />").attr("value", currentGroup[i].id).html(currentGroup[i].name).appendTo(optGroup);
        }
        optGroups.push(optGroup);
    }
}

for(var i = 0; i < optGroups.length; i++) {
    $("#products").append(optGroups[i]);
}

If you hesitate to use Underscore library, you may consider this groupBy function:

var groupBy = function(array, predicate) {
    var grouped = {};
    for(var i = 0; i < array.length; i++) {
        var groupKey = predicate(array[i]);
        if (typeof(grouped[groupKey]) === "undefined")
            grouped[groupKey] = [];
        grouped[groupKey].push(array[i]);
    }

    return grouped;
}

USAGE:

var groupData = groupBy(data, function (obj) {
    return obj.category;
});

Solution 2

I know this thread is very old, but I was needing something similar and I came up with this. It automatically adds optgroups when needed and populate them with options. Plus, it works both when you have optgroups and when you don't.

http://jsfiddle.net/mzj0nuet/

var select = $('#product');

$.each(data, function (key, cat) {
    var option = "<option value='"+cat.id+"'>"+cat.name+"</option>";

    // If we ave a category property, add this item to an optgroup
    if (cat.hasOwnProperty("category")) {
        var group = cat.category;

        // If this optgroup is not already present, add it
        if (select.find("optgroup[label='" + group + "']").length === 0) {
            select.append("<optgroup label='" + group + "' />");
        }

        select.find("optgroup[label='" + group + "']").append(option);

    // No category, no optgroup. Add this as simple option
    } else {
        select.append(option);
    }        
});
Share:
20,286
user1108276
Author by

user1108276

Updated on July 09, 2022

Comments

  • user1108276
    user1108276 almost 2 years

    I am a little bit lost. I am getting this JSON:

    [{
        "id": "210",
        "name": "Name 1",
        "category": "Category 1"
    }, {
        "id": "187",
        "name": "Name 2",
        "category": "Category 1"
    }, {
        "id": "186",
        "name": "Name 3",
        "category": "Category 1"
    }, {
        "id": "185",
        "name": "Name 4",
        "category": "Category 1"
    }, {
        "id": "184",
        "name": "Name 5",
        "category": "Category 1"
    }, {
        "id": "183",
        "name": "Name 6",
        "category": "Category 1"
    }, {
        "id": "182",
        "name": "Name 7",
        "category": "Category 1"
    }, {
        "id": "181",
        "name": "Name 8",
        "category": "Category 2"
    }, {
        "id": "180",
        "name": "Name 9",
        "category": "Category 3"
    }, {
        "id": "178",
        "name": "Name 10",
        "category": "Category 2"
    }]
    

    And I would like to put all of this in a select with options and optgroups. Actually the optgroup should be category

    I would like something like this:

    <select name="products" class="product" id="product">
    <optgroup label="Category 1">
        <option value="210">Name 1</option>
        <option value="187">Name 2</option>
        <option value="186">Name 3</option>
        <option value="185">Name 4</option>
        ...
    </optgroup>
    <optgroup label="Category 2">
        <option value="181">Name 8</option>
        <option value="178">Name 10</option>
    </optgroup>
    <optgroup label="Category 3">
        <option value="180">Name 9</option>
    </optgroup>
    

    Today I have only made this because I'm struggling too much:

    $(document).ready(function () {
        $.getJSON("5.php", {
            val: $(this).val()
        }, function (data) {
            $.each(data, function (i, item) {
                $("<option/>").attr("value", item.id).append(item.name).appendTo("optgroup");
            });
        });
    });
    

    As you can see no optgroup :) Is there a way to do this? I can also modify my JSON if it can make it easier.

    Thanks for any help.