0

I have some JSON data. I cam trying to get similar values from it. Is there any ways to use javascript to do that? I am getting my JSON from the server. But I have a sample. I am trying to load different browser versions into their optgroups.

Is there a way to do that?

JSON:

[
{
    "browser": "Amazon Silk 3.30"
},
{
    "browser": "Amazon Silk 49.2"
},
{
    "browser": "Edge 42.11"
},
{
    "browser": "Edge 42.15"
},
{
    "browser": "Google Chrome 0.01"
},
{
    "browser": "Google Chrome 0.03"
}
]

HTML

<select id="browsers" style="max-height: 150px; overflow: auto;"></select>

JavaScript

$.getJSON(jsonBrowser, function(data) {
    data.forEach((d, i) => {
        let browser_val = d.browser.replace(/ /g, "%20");
        $('#browsers').append(`<option value=${browser_val} selected>${d.browser}</option>`);
    });
});
}

Result: Right now, this code only populates by dropdown.

 Amazon Silk 3.30
 Amazon Silk 49.2
 Edge 42.11
 Edge 42.15
 Google Chrome 0.01
 Google Chrome 0.03

Result I need: I want to use optgroups in my dropdown to show:

**Amazon**:
 Amazon Silk 3.30
 Amazon Silk 49.2
**Edge**:
 Edge 42.11
 Edge 42.15
**Google**:
 Google Chrome 0.01
 Google Chrome 0.03

Is there a way to group them using JavaScript/jQuery?

nb_nb_nb
  • 1,243
  • 11
  • 36
  • Sure. How do you define the group name? The string before the first space? – Heretic Monkey Aug 06 '19 at 15:06
  • @HereticMonkey I was planning on hardcoding those. But in theory yes, its the string before the first space – nb_nb_nb Aug 06 '19 at 15:08
  • 1
    "Like" in this case just means "shares the same substring" then, so you could just get `browser_val.substring(0, browser_val.indexOf(' '))`, create an `optgroup` if one for that name doesn't exist, then go on. Sort your array first though; see [Sort array of objects by string property value](https://stackoverflow.com/q/1129216/215552). – Heretic Monkey Aug 06 '19 at 15:35

2 Answers2

0

Is the json ordered correctly? In the current state of your code the optgroups would only make sense if all similar browser appear after each other. But what if you have edge, then chrome and then edge again? In this case I would split it in 2 loops

1) loop through the json and push values into new array based on their name

2) loop through the new array and build the content

var example = [
{
    "browser": "Amazon Silk 3.30"
},
{
    "browser": "Amazon Silk 49.2"
},
{
    "browser": "Edge 42.11"
},
{
    "browser": "Edge 42.15"
},
{
    "browser": "Google Chrome 0.01"
},
{
    "browser": "Google Chrome 0.03"
},
{
    "browser": "Edge 42.13"
},
{
    "browser": "Amazon Silk 50"
}
]

var grouped_browsers = {
    'Edge': [],
    'Amazon': [],
    'Chrome': []
};
$.each(example, function() {
    if (this.browser.indexOf('Edge') !== -1) {
        grouped_browsers['Edge'].push(this.browser);
    } else if (this.browser.indexOf('Amazon') !== -1) {
        grouped_browsers['Amazon'].push(this.browser);
    } else if (this.browser.indexOf('Chrome') !== -1) {
        grouped_browsers['Chrome'].push(this.browser);
    } else {
        grouped_browsers['Other'].push(this.browser);
    }
});

var rendered_groups = '';
var formatted_browsers = {
    'Amazon': 'Amazon Silk',
    'Chrome': 'Google Chrome',
    'Edge': 'Edge'
};
$.each(grouped_browsers, function(key, value) {
    rendered_groups += '<optgroup label="'+formatted_browsers[key]+'">';
    $.each(value, function() {
        rendered_groups += '<option value="'+this+'">'+this+'</option>';
    });
    rendered_groups += '</optgroup>';

});
$('#browsers').html(rendered_groups);

I made a fiddle with a simple solution https://jsfiddle.net/rLbzs1ky/1/.

Insomnia88
  • 378
  • 2
  • 13
  • well my code works in both ways. But it can be optimized quite a bit. Maybe I will add a less complex version later considering that you know the order – Insomnia88 Aug 06 '19 at 15:39
0

You could use Array.prototype.reduce in combination with String.prototype.split to create a sort of map. Something like this:

const arr = [{
  "browser": "Amazon Silk 3.30"
}, {
  "browser": "Amazon Silk 49.2"
}, {
  "browser": "Edge 42.11"
}, {
  "browser": "Edge 42.15"
}, {
  "browser": "Google Chrome 0.01"
}, {
  "browser": "Google Chrome 0.03"
}];

const groupBrowser = (accum, el) => {
  const [groupName] = el.browser.split(' '); //Group by the first word in the string
  if (accum[groupName]) {
    accum[groupName].push(el.browser);
  } else {
    accum[groupName] = [el.browser];
  }
  return accum;
};

//Use the DOM API to create option elements for each group
const generateOptgroupEls = entry => {
  const [key, val] = entry;
  const optgroupEl = document.createElement('optgroup');
  optgroupEl.label = `**${key}**`;

  val.forEach(browser => {
    const optionEl = document.createElement('option');
    optionEl.value = browser;
    optionEl.text = browser;
    optgroupEl.appendChild(optionEl);
  });

  return optgroupEl;
};

//Create the select DOM el we will load up with options
const selectEl = document.createElement('select');

//Group the data
const groups = arr.reduce(groupBrowser, {});

//Create optgroup DOM elements based on group data
const optgroupEls = Object.entries(groups).map(generateOptgroupEls);

//Append the optgroups to the select el
optgroupEls.forEach(optgroupEl => {
  selectEl.appendChild(optgroupEl);
});

//Append the select el to the document
document.querySelector('#target').appendChild(selectEl);
<div id="target"></div>
Tom O.
  • 5,730
  • 2
  • 21
  • 35