Assuming I have a fairly complex JSON object such as the one below:
{
"firstName": "John",
"address": [{
"streetAddress": "1 street",
"special": {
"1 a": "1 b"
}
}, {
"streetAddress": "2 naist street",
"special": {
"2 a": "2 b"
}
}],
"phoneNumbers": [{
"type": "iPhone",
"number": "0123-4567-8888"
}]
}
Are there any tools/libraries to calculate the JSONPath to a particular key/value pair?
For example: the JSONPath to the third row of data (streetAddress": "1 street") can be extracted using the JSONPath $.address[0].streetAddress.
Ideally I want something like this: calculateJSONPath(3) - where 3 is the 3rd key starting from the top and this function will return $.address[0].streetAddress. I don't imagine there'll be something that does exactly this, but I got to start somewhere, if not from scratch.
Edit: Sample use case: User loads a JSON file into my application. I allow them to select specific keys using my interface. Imagine checkboxes next to each key. Next the user can upload a second JSON file and see if the previously selected keys/values are present in the second JSON.
Edit 2: Searching won't work as I want the key/values selected by the user to be located in the same hierarchy as the first JSON. Eg: If the user selects "1 a": "1 b" in the first JSON file, the second JSON file must have the same key/value in the same nested hierarchy.
Here is a taste of what I said (check an checkbox to see my point):
var $ = {
"firstName": "John",
"address": [{
"streetAddress": "1 street",
"special": {
"2 a": "2 a"
}
}, {
"streetAddress": "2 naist street",
"special": {
"2 a": "2 a"
}
}],
"phoneNumbers": [{
"type": "iPhone",
"number": "0123-4567-8888"
}]
};
// the recursive function that create the structure
function createStructure(container, obj, path) {
for(var key in obj) {
var d = cd(key, path);
if(typeof obj[key] == "object")
createStructure(d, obj[key], path + "['" + key + "']");
container.appendChild(d);
}
}
// of course we call the function ...
createStructure(document.getElementById("preview"), $, "$");
// create a preview element (unimportant)
function cd(prop, path) {
var d = document.createElement("div");
var s = document.createElement("span");
var i = document.createElement("input");
i.setAttribute("data-path", path + "['" + prop +"']");
i.onclick = check;
i.type = "checkbox";
s.appendChild(i);
s.appendChild(document.createTextNode(prop));
d.appendChild(s);
return d;
}
// the event handler (unimportant)
function check(e) {
if(e.target.checked)
alert(e.target.getAttribute("data-path"));
}
div {
padding: 5px;
padding-left: 25px;
}
span {
border-bottom: 1px solid black;
border-left: 1px solid black;
}
<div id="preview">
<span><input type="checkbox" data-path="$"/>$</span>
</div>
The following will create an DOM-structure from the supplied JSON. It's very rudimentary and it's just a proof of concept.
You will need to build the rest of the application from this foundation.
Every level (UL) has an index and every item (LI) a key.
//rework JSON into a structure
function buildDOMFromJSON()
{
var JSONString = document.querySelector("#uploadedJSON1").value;
//you need to add a gazillion error checks
var JSONcompiled = JSON.parse(JSONString);
//test if array or object
var start, isObject;
if (JSONcompiled instanceof Array)
{
start = JSONcompiled;
isObject = false;
}
else //is object
{
start = Object.keys(JSONcompiled); //create an array to start
isObject = JSONcompiled;
}
loopJSONLevel(start, isObject, document.querySelector("#JSONstructure1 > ul"));
}
function loopJSONLevel(obj, isObject, level)
{
//loop the array
obj.forEach(function(element, index){
var objectToEvaluate;
if (isObject == false)
{
objectToEvaluate = element;
}
else
{
objectToEvaluate = isObject[element];
}
//create a new level
var newLevel = document.createElement("li");
var newLevel2 = document.createElement("ul");
if (objectToEvaluate instanceof Array)
{
//create a new level
if (element instanceof Array)
{
newLevel2.setAttribute("data-path", index);
}
else
{
newLevel2.setAttribute("data-path", element);
}
level.appendChild(newLevel2);
loopJSONLevel(objectToEvaluate, false, newLevel2);
}
else if (Object.prototype.toString.call(objectToEvaluate) == "[object Object]")
{
//create a new level
if (element instanceof Array)
{
newLevel2.setAttribute("data-path", index);
}
else
{
newLevel2.setAttribute("data-path", element);
}
newLevel2.setAttribute("data-path", index);
level.appendChild(newLevel2);
loopJSONLevel(Object.keys(objectToEvaluate), objectToEvaluate, newLevel2);
}
else
{
//draw the value
level.appendChild(newLevel);
newLevel.textContent = objectToEvaluate;
newLevel.setAttribute("data-path", element);
}
});
}
buildDOMFromJSON()
<textarea id="uploadedJSON1">
[{
"firstName": "John",
"address": [{
"streetAddress": "1 street",
"special": {
"1 a": "1 b"
}
}, {
"streetAddress": "2 naist street",
"special": {
"2 a": "2 b"
}
}],
"phoneNumbers": [{
"type": "iPhone",
"number": "0123-4567-8888"
}]
}]
</textarea>
<div id="JSONstructure1">
<ul>
</ul>
</div>
I have done the same thing using Angular.
You can see an example below :
https://davicvictor.github.io/jsonpath-ui/ and open your console.
Related
Got an object containing a user id for each user and prices, would like to create a new object/array for each user (no duplicates) and be able to calculate the total sum of price for each user. Tried using Object.values() with map and filter but can't get it to work properly
{
"data": {
"item1": {
"price": "20",
"user": "user1"
},
"item2": {
"price": "10",
"user": "user2"
},
"item3": {
"price": "50",
"user": "user1"
}
}
}
Output something like this:
{
"users": {
"user1": {
"totalSum": "70",
},
"user2": {
"totalSum": "10",
}
}
}
I'm thinking about using map to present the "users"-data, maybe an array would be better?
Using function reduce.
Important: The attribute price is a String, this approach uses object Number to convert that value to a numeric one.
var obj = { "data": { "item1": { "price": "20", "user": "user1" }, "item2": { "price": "10", "user": "user2" }, "item3": { "price": "50", "user": "user1" } }};
var result = Object.keys(obj.data).reduce((a, k) => {
if (a.users[obj.data[k].user]) {
a.users[obj.data[k].user].totalSum += Number(obj.data[k].price);
} else {
a.users[obj.data[k].user] = {
"totalSum": Number(obj.data[k].price)
}
}
return a;
}, {
'users': {}
});
console.log(result);
.as-console-wrapper {
max-height: 100% !important; top: 0;
}
You could leverage ```reduce, more information here
code (haven't tried this)
var data = JSON.parse(mainObj).data;
var usersWithTotalExpenditure = Object.keys(data).reduce(function(result, key) {
var currentItem = data[key];
var useName = currentItem.user;
var price = Number(currentItem.price);
if (userName in result) {
result[userName].totalSum += price;
} else {
result[userName] = {
totalSum: price
};
}
return result;
}, {});
var resultObject = {
users: usersWithTotalExpenditure
}
You can use a forEach loop. This relies on Javascripts powerful OR operator, which coerces the first half of the expression to false if the current user's price is not defined (meaning it is a user the loop hasn't encountered before)
`c is your initial object's data, output is empty object`
const c = obj.data;
var output = {};
Object.keys(c).forEach((val) => {
output[c[val]["user"]] = parseInt(output[c[val]["user"]]) + parseInt(c[val]["price"]) || parseInt(c[val]["price"]);
})
I've got an array of three people. I want to add a new key to multiple objects at once based on an array of indices. Clearly my attempt at using multiple indices doesn't work but I can't seem to find the correct approach.
var array = [
{
"name": "Tom",
},
{
"name": "Dick",
},
{
"name": "Harry",
}
];
array[0,1].title = "Manager";
array[2].title = "Staff";
console.log(array);
Which returns this:
[
{
"name": "Tom",
},
{
"name": "Dick",
"title": "Manager"
},
{
"name": "Harry",
"title": "Staff"
}
]
But I'd like it to return this.
[
{
"name": "Tom",
"title": "Manager"
},
{
"name": "Dick",
"title": "Manager"
},
{
"name": "Harry",
"title": "Staff"
}
]
You cannot use multiple keys by using any separator in arrays.
Wrong: array[x, y]
Correct: array[x] and array[y]
In your case, it will be array[0].title = array[1].title = "manager";
1st method::
array[0].title = "Manager";
array[1].title = "Manager";
array[2].title = "Staff";
array[0,1] will not work.
2nd method::
for(var i=0;i<array.length;i++) {
var msg = "Manager";
if(i===2) {
msg = "Staff"
}
array[i].title = msg
}
You can use a helper function like this
function setMultiple(array, key, indexes, value)
{
for(i in array.length)
{
if(indexes.indexOf(i)>=0){
array[i][key] = value;
}
}
}
And then
setMultiple(array, "title", [0,1], "Manager");
Try this: `
for (var i=0; var<= array.length; i++){
array[i].title = "manager";
}`
Or you can change it around so var is less than or equal to any n range of keys in the index.
EDIT: instead make var <= 1. The point is to make for loops for the range of indices you want to change the title to.
Assuming that you have a bigger set of array objects.
var array = [
{
"name": "Tom",
},
{
"name": "Dick",
},
{
"name": "Harry",
},
.
.
.
];
Create an object for the new keys you want to add like so:
let newKeys = {
'Manager': [0,2],
'Staff': [1]
}
Now you can add more such titles here with the required indexes.
with that, you can do something like:
function addCustomProperty(array, newKeys, newProp) {
for (let key in newKeys) {
array.forEach((el, index) => {
if (key.indexOf(index) > -1) { // if the array corresponding to
el[newProp] = key // the key has the current array object
} // index, then add the key to the
}) // object.
}
return array
}
let someVar = addCustomProperty(array, newKeys, 'title')
Trying to understand JavaScript and writing to objects. I have an object here:
{
"name":"",
"children":[
{
"name":"Level 1",
"children":[
{
"name":"Level 2",
"children":[
{
"name":"Level 3",
"children":[
{
"name":"Level 4",
"children":[
{
"name":"Speed",
"children":null,
"id":6
}
],
"id":5
}
],
"id":4
}
],
"id":3
}
],
"id":2
},
{
"name":"Level 1",
"children":[
{
"name":"Level 2",
"children":[
{
"name":"Level 3",
"children":[
{
"name":"Level 4",
"children":[
{
"name":"Cost",
"children":null,
"id":11
}
],
"id":10
}
],
"id":9
}
],
"id":8
}
],
"id":7
},
{
"name":"Level 1",
"children":[
{
"name":"Level 2",
"children":[
{
"name":"Level 3",
"children":[
{
"name":"Level 4",
"children":[
{
"name":"Manufacturability",
"children":null,
"id":16
}
],
"id":15
}
],
"id":14
}
],
"id":13
}
],
"id":12
}
],
"id":1
}
and I'm trying to understand how to search for a given id value and change its name value.
In my case, I know that I can access values using d.id and d.name using the code below (this is part of a widget display; the name values populate it)
var jstring = this.model.get('value') ? this.model.get('value') : "{}";
// where 'value' = demo.json
var root = JSON.parse(jstring)
var g = this.g = svg.selectAll("g")
.data(partition.nodes(root))
.enter().append("g");
var path = this.path = g.append("path")
.attr("d", arc)
.style("fill", function(d) {
d.active = d.active ? true : false
return d.active || d.center ? color[1] : color[0];
})
.on("dblclick",dblclick);
var text = this.text = g.append("text")
.attr("transform", function(d) { return "rotate(" + computeTextRotation(d) + ")"; })
.attr("x", function(d) { return y(d.y); })
.attr("dx", "6") // margin
.attr("dy", ".35em") // vertical-align
.text(function(d) { return d.name; });
For example, if I click on a certain area on the widget, I can populate an input box by setting its value to d.name and it gives me the correct value.
function dblclick(d)
{
var input = document.getElementById("name");
input.value = d.name;
$( "#dialog" ).dialog(
{
buttons: {
Save: function() {
d.name = input.value;
var newString = JSON.stringify(root, function(key, val) {
if (Array.isArray(val)){
return val
}
if (val != null && typeof val == "object") {
val = _.pick(val, 'name', 'children', 'id');
if(d.id == val.id){
input.value = d.name;
console.log(d.name)
}
val.children = Array.isArray(val.children) ? val.children : [];
return val
}
return val
})
self.model.set('value', newString)
self.update()
console.log(newString)
I found a similar question here but I don't understand how to apply the answer to modify my JSON.
Also here is a fiddle of what I've tried: http://jsfiddle.net/CVvW4/237/ . I followed an answer from another question but my implementation is wrong.
Your jsonStr is already a json object, no need to stringify and parse it
You have a nested structure, to find something you will need a recursive function
Here is how to find a node given its id:
var root = jsonStr
function findById(node, id) {
if (node.id == id) return node; // we found the node with the id given, return it
var result = null; // if the id wasn´t the one we were looking, we need to look if it is in its children
if (node.children) {
for (var i = 0; i < node.children.length && result == null; i++) {
result = findById(node.children[i], id)
}
}
return result; // return null if it wasn´t in its children, return the node if it was
}
console.log(findById(root, 16))
Now, to change its name you can simply do:
findById(root, 16).name = 'asd';
I really like the accepted answer provided by #juvian which I up-voted.
I provide this one to show how you can name the child array and the property we wish to match on for the node. I also protect the array iteration by type.
I provide here some details regarding JSON, JavaScript Objects and when to parse, when not to parse by providing some examples of each.
Note that I added a small function typeName to assist in discovery of names and thus we do not attempt to iterate a non-array type (null one, string etc.) by the same name as the property we are searching for.
NOTE: I did NOT protect against the type matching of the property against the searchFor value but if that was important, string "1" vs number 1 you could put in an enhancement using the typeName as well.
Example to play with: https://jsfiddle.net/MarkSchultheiss/s4sxy4f6/
HERE is a stripped down version where I check for success prior to trying to assign the name to it: https://jsfiddle.net/MarkSchultheiss/s4sxy4f6/1/
Code and objects to show types:
// this is just a string, but special as it is a JSON string and can be parsed
var myJSON = '{"children":[{"children":[{"children":[{"children":[{"children":[{"children":null,"id":6,"name":"Speed"}],"id":5,"name":"Level 4"}],"id":4,"name":"Level 3"}],"id":3,"name":"Level 2"}],"id":2,"name":"Level 1"},{"children":[{"children":[{"children":[{"children":[{"children":null,"id":11,"name":"Cost"}],"id":10,"name":"Level 4"}],"id":9,"name":"Level 3"}],"id":8,"name":"Level 2"}],"id":7,"name":"Level 1"},{"children":[{"children":[{"children":[{"children":[{"children":null,"id":16,"name":"Manufacturability"}],"id":15,"name":"Level 4"}],"id":14,"name":"Level 3"}],"id":13,"name":"Level 2"}],"id":12,"name":"Level 1"}],"_default":{},"id":1,"name":""}';
// This is a JavaScript Object
var myObject = {
"children": [{
"children": [{
"children": [{
"children": [{
"children": [{
"children": null,
"id": 6,
"name": "Speed"
}],
"id": 5,
"name": "Level 4"
}],
"id": 4,
"name": "Level 3"
}],
"id": 3,
"name": "Level 2"
}],
"id": 2,
"name": "Level 1"
}, {
"children": [{
"children": [{
"children": [{
"children": [{
"children": null,
"id": 11,
"name": "Cost"
}],
"id": 10,
"name": "Level 4"
}],
"id": 9,
"name": "Level 3"
}],
"id": 8,
"name": "Level 2"
}],
"id": 7,
"name": "Level 1"
}, {
"children": [{
"children": [{
"children": [{
"children": [{
"children": null,
"id": 16,
"name": "Manufacturability"
}],
"id": 15,
"name": "Level 4"
}],
"id": 14,
"name": "Level 3"
}],
"id": 13,
"name": "Level 2"
}],
"id": 12,
"name": "Level 1"
}],
"_default": {},
"id": 1,
"name": ""
};
// just to get the name of the objects type from the object prototype
function typeName(obj) {
// splits and returns second part of string such as "[object Array]" returns the "Array" removing the closing bracket
return Object.prototype.toString.call(obj).match(/.* (.*)\]/)[1];
}
// show some type names to assist with object "type" education
console.log("myJSON:" + typeName(myJSON)); // String
console.log("myObject:" + typeName(myObject)); // Object
console.log("Children of object:" + typeName(myObject.children)); // Array
console.log("Children Type:" + typeof myObject["children"] + " typeName:" + typeName(myObject.children));
console.log(Object.keys(myObject)); // thus we can get the string "children" from the object with Object.keys(myObject)[0]
var root = JSON.stringify(myObject); // create string of object
console.log("root:" + typeName(root)); // String
var newObject = JSON.parse(myJSON); // create new object of string
// create function with private name to call internally
// done this way to allow for external modification of the name without need to change the code inside it.
var findByProperty = function findNext(node, searchValue, propertyName, childName) {
if (node.hasOwnProperty(propertyName) && node[propertyName] == searchValue) return node; // node found return it
var result = null;
// has child array by the name and it is non-empty array
if (node.hasOwnProperty(childName) && typeName(node[childName]) === 'Array' && node[childName].length) {
for (var i = 0; i < node[childName].length && result == null; i++) {
result = findNext(node[childName][i], searchValue, propertyName, childName);
}
}
return result; // return null if not in children, return the node if it was
}
var searchFor = 16;
console.log('searchFor is a type of:'+typeName(searchFor));
var propertyName = "id";
var childrenArrayName = "children";
// show how we can return the found node then modify it
var found = findByProperty(myObject, searchFor, propertyName, childrenArrayName);
found.name = 'Freddy';
console.log(myObject);
console.log(myObject["children"][2]["children"][0]["children"][0]["children"][0]["children"][0].name); // logs "Freddy"
var secondfound = findByProperty(newObject, searchFor, propertyName, childrenArrayName);
secondfound.name = 'Walter';// modify the object via the node
console.log(newObject);
console.log(newObject["children"][2]["children"][0]["children"][0]["children"][0]["children"][0].name); // logs "Walter"
// just to show that the actual object is the one found
console.log(secondfound.name === newObject["children"][2]["children"][0]["children"][0]["children"][0]["children"][0].name); // logs true
Here is the output of the console logs:
myJSON:String
VM78:125 myObject:Object
VM78:126 Children of object:Array
VM78:128 Children Type:object typeName:Array
VM78:129 ["children", "_default", "id", "name"]
VM78:132 root:String
VM205:148 searchFor is a type of:Number
VM281:153 Object {children: Array[3], _default: Object, id: 1, name: ""}
VM281:154 Freddy
VM337:158 Object {children: Array[3], _default: Object, id: 1, name: ""}
VM337:159 Walter
VM344:160 true
I have an object which at some points is four levels deep, however I want a function that will cope should more levels be introduced. I'm trying to write a function that will replaced elements such that <span class="ajax-parent1-parent2-parent3-value"></span> will be replaced with parent1.parent2.parent3.value.
The issue is that the depth is variable, so I could have something like <span class="ajax-parent1-value"></span> to be replaced with parent1.value.
Finally, it's not always the text to be replaced. Optionally, data-attr can specify an attribute to be used instead (through element.attr(<data-attr>, <value>)).
Currently, I'm iterating manually, however it isn't very clean so I was wondering if there is a better way to do it. This also doesn't work for greater than two levels deep.
function render(data) {
$.each(data, function(parent, value) {
$.each(value, function(element, value) {
$el = $('.ajax-' + parent + '-' + element);
$.each($el, function(key, el) {
if ($(el).data('attr')) {
$(el).attr($(el).data('attr'), value);
} else {
$(el).text(value);
}
}
});
});
}
Example object:
{
"profile": {
"username": "johnd",
"bio": "Some example data about John",
"website": "http://john.com",
"profile_picture": "http://john.com/me.jpg",
"full_name": "John Doe",
"counts": {
"media": 13,
"followed_by": 26,
"follows": 49
},
"id": "16"
},
"dashboard": {
"script": {
"tags": ["media"],
"stats": {
"liked": 0,
"lastrun": "never",
"duration": 0
},
"status": {
"code": 0,
"slug": "disabled",
"human": "Disabled",
"message": "Not running."
}
},
"account": {
"plan": "free",
"created": 1419261005373,
"updated": 1419261005373
}
},
"serverInformation": {
"serverName": "Johns API",
"apiVersion": "0.0.1",
"requestDuration": 22,
"currentTime": 1419262805646
},
"requesterInformation": {
"id": "redacted",
"fingerprint": "redacted",
"remoteIP": "redacted",
"receivedParams": {
"action": "getDashboard",
"apiVersion": 1
}
}
}
Here is the solution I wrote:
function iterate(obj, stack) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property], stack + '-' + property);
} else {
$group = $('.ajax' + stack + '-' + property);
$.each($group, function(key, element) {
if ($(element).data('attr')) {
$(element).attr($(element).data('attr'), obj[property]);
} else {
$(element).text(obj[property]);
}
});
}
}
}
}
Why don't you start from the HTML, so you only access the properties you actually want to render?
That way you can keep it quite simple (also note that this removes the need to nest HTML spans in the same order/depth as the data object, you can just place any HTML node anywhere. Just make sure you don't use class/node names more then once.
function parseData(data) {
var $container = $('.ajax');
$container.find("[class^='ajax-']").each(function(i, el) {
var $el = $(el);
if ($el.children().length === 0)
{
var nodes = $el.attr('class').split('-');
nodes.shift();
var node = data;
for (var i = 0; i < nodes.length; i++) {
node = node[nodes[i]];
if (typeof(node) == "undefined") {
break;
}
}
if ($el.data('attr'))
{
$el.attr($el.data('attr'), node);
}
else
{
$el.text(node);
}
}
});
}
Fiddle here:
http://jsfiddle.net/ckcduLhn/5/
I'm trying to form a list from json data, see the example What I want is that it will show me the value just once when duplicate values occurs (2x Martini glass, I want it to return just one in the list), but leaves the array as is, i.e. still want to be able to hold all values in the array.
There'd sure be a simple way to achieve this, but i'm not finding it...
var data = {
"cocktails": [{
"name": "Bloody Mary",
"glass": "longdrink",
"ingredients": {
"main": "vodka",
"secondary": "tomato juice",
"addition": "tabasco"
}
}, {
"name": "Daiquiri",
"glass": "martini glass",
"ingredients": {
"main": "white rum",
"secondary": "lime juice",
"addition": "sugar syrup"
}
}, {
"name": "Martini",
"glass": "martini glass",
"ingredients": {
"main": "gin",
"secondary": "vermout",
"addition": "olive"
}
}]
}
$(data.cocktails).each(function () {
var output = "<ul><li>" + this.glass + "</li></ul>";
$('#placeholder').append(output);
});
Create an empty array:
var glasses = [];
Push all the glasses to it.
data.cocktails.forEach(function (el) {
glasses.push(el.glass);
});
Create a deduped array of glasses. This leaves the glasses array intact so you can use it again.
var dedupedGlasses = glasses.filter(function(elem, pos) {
return glasses.indexOf(elem) == pos;
});
Use join to create the HTML list.
var html = '<ul><li>' + dedupedGlasses.join('</li><li>') + '</li></ul>';
And add to the page.
$('#placeholder').append(html);
Demo
The you can use something like this to grab the count for each glasses type:
function getCount(arr) {
return arr.reduce(function(m, e){
m[e] = (+m[e]||0)+1; return m
}, {});
}
console.log(getCount(glasses)); // { longdrink=1, martini glass=2 }
Basically the same as #Andy, though slightly different.
var data = {
"cocktails": [{
"name": "Bloody Mary",
"glass": "longdrink",
"ingredients": {
"main": "vodka",
"secondary": "tomato juice",
"addition": "tabasco"
}
}, {
"name": "Daiquiri",
"glass": "martini glass",
"ingredients": {
"main": "white rum",
"secondary": "lime juice",
"addition": "sugar syrup"
}
}, {
"name": "Martini",
"glass": "martini glass",
"ingredients": {
"main": "gin",
"secondary": "vermout",
"addition": "olive"
}
}]
}
$('#placeholder').append('<ul><li>' + data.cocktails.map(function (cocktail) {
return cocktail.glass;
}).filter(function (glass, index, array) {
return array.indexOf(glass) === index;
}).join('</li><li>') + '</li></ul>');
On jsFiddle
I can just point to a solution where you need to define a new array
var cleanArr = []
$(data.cocktails).each(function () {
if($.inArray(this.glass, cleanArr) === -1) cleanArr.push(this.glass);
var output = "<ul><li>" + this.glass + "</li></ul>";
$('#placeholder').append(output);
});
console.log(cleanArr)
I like the way the array is created, that's why I'm posting this solution but it is not my idea --> taken from:
Remove Duplicates from JavaScript Array
Here is a working jsFiddle for you.
http://jsfiddle.net/Q74pj/1/
And here is what I did:
I used a new function calling uniqueArray to create a new associative array (which would be the quickest to iterate and fill).
You need to create a unique array, or sort it by drink and skip the duplicates.
function uniqueValues (arr) {
//if (arr.length < 2) return arr;
var retVal = {};
for (var i = 0; i < arr.length; i++) {
retVal[arr[i].glass] = arr[i];
}
return retVal;
}
then just use another way to iterate the associate array:
var uniqueArrayValues = uniqueValues(data.cocktails);
for (key in uniqueArrayValues) {
var output = "<ul><li>" + uniqueArrayValues[key].glass + "</li></ul>";
$('#placeholder').append(output);
}