If you had a data structure that corresponded to HTML, it would be much easier to reason.
given
[ { "Type" : "Overdrive", "Brand" : "Chase Bliss", "Name" : "Brothers", "Width" : 2.75, "Height" : 4.77, "Image" : "public/images/pedals/chasebliss-brothers.png" } ]
while you need structure
<select> <optgroup label="Chase Bliss"> <option data-width="..." data-height="..." data-image="...">Chase Bliss Brothers</option> </optgroup> </select>
Instead of trying to do this conversion from JSON to HTML, create a new data structure that matches the HTML. If the data structure matches the HTML structure, the logic of its visualization will be much simpler.
Something like the following will work well.
[ { brandName: "Chase Bliss", items: [ { name: "Brothers" } ] } ]
You can write a reduction function to do this conversion:
let optionGroups = pedals.reduce((optionGroups, pedal) => { let optionGroup = optionGroups.find(group => pedal.Brand === group.brandName) || {} if (!optionGroup.brandName) { optionGroup.brandName = pedal.Brand optionGroup.items = [] optionGroups.push(optionGroup) } optionGroup.items.push(pedal) return optionGroups }, [])
the rendering function can then simply display the external elements and then the internal elements.
window.renderPedals = (optionGroups) => { optionGroups.map((group) => { let $optgroup = $("<optgroup>", { label: group.brandName }); group.items.map((pedal) => { let {Type, Brand, Name, Width, Height, Image} = pedal; let $pedal = $("<option>", { text: `${Brand} ${Name}`, id: `${Name.toLowerCase().replace(/\s+/g, "-").replace(/'/g, '')}`, data: { width: Width, height: Height, image: Image }, appendTo: $optgroup }); }) $optgroup.appendTo(".pedal-list"); }) }
https://jsfiddle.net/f4x9vk0f/2/