I am new to javascript & jquery, Need to remove an element from the below array structure
[{
"tag": "tag1",
"description": "description1"
}, {
"tag": "tag2",
"description": "description2"
}, {
"tag": "tag3",
"description": "description3"
}]
The element to be removed is known {"tag":"tag2", "description":"description2"}.
How can i find this element and remove from the array.
Please find the code which i am using to remove an element
var actionDic = [];
actionDic.push({
description: desc,
tag: tag
});
The actionDic array is populated as user enter text in textinput and selects 'add' option.
var deleterow = {
tag: "tag2",
description: "description2"
};
var index = $.inArray(deleterow, actionDic);
if (index != -1) {
actionDic.splice(index, 1);
}
The correct index is not obtained. Kindly let me know what wrong is in the code.
Thanks.
Since the comparison between the item to remove and each element in actionDic isn't trivial, you could use jQuery.grep():
actionDic = jQuery.grep(actionDic, function(elem) {
return elem.tag == deleterow.tag && elem.description == deleterow.description;
}, true);
Demo
It performs a search using a custom search function and returns the array elements that didn't match. The result replaces the previous value of actionDic and effectively removed that one item.
Update
Unfortunately, this method could be considered heavy because a new array gets created at each invocation; both in terms of what jQuery can do and standard JavaScript functionality, this particular feature is lacking. ECMAScript 6 will have the Array.prototype.find() method that will do the job of finding the index in an array (with which you can perform the splice).
You can of course write one yourself too:
(function($) {
$.find = function(arr, fn) {
for (var i = 0, len = arr.length; i < len; ++i) {
if (fn(arr[i], i, arr)) {
return i;
}
}
return -1;
};
}(jQuery));
var index = $.find(actionDic, function(elem) {
return elem.tag == deleterow.tag && elem.description == deleterow.description;
});
if (index != -1) {
actionDic.splice(index, 1);
}
Demo
I've implemented an indexOfObject method of Array prototype in one of my projects. It searches for an index of object by the given property name and value. Here it is:
Array.prototype.indexOfObject = function(searchTerm, property) {
for (var i = 0, l = this.length; i < l; i++) {
if (this[i][property] === searchTerm) {
return i;
}
}
return -1;
};
You can use this method to find the index of your object using a unique property. In your case you can use it like this:
var arr = [{
"tag": "tag1",
"description": "description1"
}, {
"tag": "tag2",
"description": "description2"
}, {
"tag": "tag3",
"description": "description3"
}], deleteObject = {
tag: "tag2",
description: "description2"
};
var index = arr.indexOfObject(deleteObject.tag, 'tag');
Then you can use that index to remove the object from the array:
if (index > -1) {
arr.splice(index, 1);
}
Here is the working example in JSFiddle.
var actionDic = [{
"tag": "tag1",
"description": "description1"
}, {
"tag": "tag2",
"description": "description2"
}, {
"tag": "tag3",
"description": "description3"
}]
var element = {"tag":"tag2", "description":"description2"}
for(var i=0;i<actionDic.length;i++) {
var found = false;
for(each in actionDic[i]) {
if(actionDic[i][each] == element[each]) {
found = true
} else {
found = false;
break;
}
}
if(found) {
actionDic.splice(i,1);
found=false;
}
}
This gets your inner array objects:
for (var x = 0; x < actionDic.length; x++){
var arrayItem = actionDic[x];
if (arrayItem["tag"] == "tag2"){
alert(arrayItem["description"]);
}
}
Working fiddle: http://jsfiddle.net/4khjp/
You can use underscore.js which contains many useful helpers for Objects, Arrays etc.
Removing array element:
array = _.reject(array, function(item) {
return item.tag == 'tag2'; // <- if tag is unique to whole array
});
Related
I need to reformat the following JSON data
[
{
"name": "Hello",
"value": 1
},
{
"name": "Hello",
"value": 11
},
{
"name": "Bye",
"value": 2
},
{
"name": "Bye",
"value": 22
}
]
to this:
[
{
"Hello": 1,
"Bye": 2
},
{
"Hello": 11,
"Bye": 22
},
]
There will always be an object with the same "name" field (but a different value in the "value" field) right after. I am stuck and not sure how to solve this. Is it possible to do using Lodash or pure JavaScript?
I have never before heard of Lodash, but in pure JS this can be solved with two nested loops:
function myConvert(long)
{
var short = [];
for(var i = 0; i < long.length; i++)
{
var key = long[i].name;
var value = long[i].value;
var object = null;
for(var j = 0; j < short.length; j++)
{
if(short[j][key] === undefined)
{
object = short[j];
break;
}
}
if(object === null)
{
object = {};
short.push(object);
}
object[key] = value;
}
return short;
}
This is basically:
Iterate over all elements of long.
For each of those, iterate over all elements of short to find the first element where the current name as key is not defined.
Create a new object, if not found.
Add the current value to object with name as key.
Yes there are many post regarding this.But my doubt is little different.I have following array for example
var dictionary = {
"12Jan2013": [{
"id": "0",
"name": "ABC"
}, {
"id": "1",
"name": "DEF"
}],
"13Jan2013": [{
"id": "0",
"name": "PQR"
}, {
"id": "1",
"name": "xyz"
}]
};
Same post is there on same site BUT here in dictionary json array key is dynamic.Here it is date ie 12Jan2013.It can be any date.It is not static.I have searched for that but didn't get solution.
How to iterate over such a json array?
AND How to print json array as in same formate shown above?
EDIT
Here is my real code.And i shown a comment in following code where i wanted to iterate data ie jsonData var in getWeatherDataForCities callback
var arrAllrecords = [];
var arrCityrecordForADay = [];
function getWeatherDataForCities(cityArray, callback){
var toDaysTimestamp = Math.round((new Date()).getTime() / 1000) - (24*60*60);
for(var i in cityArray){
for(var j=1; j<=1; j++){
var jsonurl = "http://api.openweathermap.org/data/2.5/history/city?q="+cityArray[i]+"&dt="+toDaysTimestamp;
$.ajax({
url: jsonurl,
dataType: "jsonp",
mimeType: "textPlain",
crossDomain: true,
contentType: "application/json; charset=utf-8",
success: function(data){
var arrCityRecordForDay = [];
/*arrCityrecordForADay.push(data.list[0].city.name);
arrCityrecordForADay.push(data.list[0].weather[0].description);
arrCityrecordForADay.push(timeConverter(data.list[0].dt));
arrCityrecordForADay.push(data.list[0].main.temp);
arrCityrecordForADay.push(data.list[0].main.humidity);
arrCityrecordForADay.push(data.list[0].main.pressure)
arrCityrecordForADay.push(data.list[0].wind.speed);*/
//'{"pets":[{"name":"jack"},{"name":"john"},{"name":"joe"}]}';
arrCityRecordForDay.push(
{"cityName" : data.list[0].city.name},
{"weather" : data.list[0].weather[0].description}
);
var tempId = data.list[0].city.name+"-"+timeConverter(data.list[0].dt);
arrCityrecordForADay.push(
{tempId : arrCityRecordForDay}
);
if(((arrCityrecordForADay.length)) === cityArray.length) {
callback(arrCityrecordForADay);
}
} });
toDaysTimestamp = toDaysTimestamp - (24*60*60);
}
}
}
$(document ).ready(function() {
var cityArray = new Array();
cityArray[0] = "pune";
getWeatherDataForCities(cityArray, function(jsonData) {
// Here I want to iterate jsonData
});
});
Use for-in...something like:
for (var i in dictionary) {
dictionary[i].forEach(function(elem, index) {
console.log(elem, index);
});
}
where the i would iterate through your dictionary object, and then you can use forEach for every json array in the dictionary(using dictionary[i])
With this code you'll get
Object {id: "0", name: "ABC"} 0
Object {id: "1", name: "DEF"} 1
Object {id: "0", name: "PQR"} 0
Object {id: "1", name: "xyz"} 1
You can tailor the forEach function definition(replacing the console.log bit) to do whatever you want with it.
DEMO
Edit: Doing the same thing using Object.keys
Object.keys(dictionary).forEach(function(key) {
dictionary[key].forEach(function(elem, index) {
console.log(elem, index);
});
});
Edit2: Given the somewhat complicated structure of your jsonData object, you could try using a (sort of) all-purpose function that would act on each type of component separately. I've probably missed a few cases, but maybe something like:
function strung(arg) {
var ret = '';
if (arg instanceof Array) {
arg.forEach(function(elem, index) {
ret += strung(elem) + ',';
});
} else if (arg instanceof Object) {
Object.keys(arg).forEach(function(key) {
ret += key + ': /' + strung(arg[key]) + '/';
});
} else if (typeof arg === "string" || typeof arg === "number") {
ret = arg;
}
return ret;
}
document.body.innerHTML = strung(jsonData);
DEMO
Please note that yours is just a JavaScript array object. To make it simple to understand, you can iterate over it like this:
for (var i in dictionary) {
// do something with i
// here i will contain the dates
for (n = 0; n < dictionary[i].length; n++) {
// do something with the inner array of your objects
// dictionary[i][n].id contains the "id" of nth object in the object i
// dictionary[i][n].name contains the "name" of nth object in the object i
}
}
See this fiddle: http://jsfiddle.net/Ke8F5/
The iteration looks like this:
12Jan2013 : (id = 0, name = ABC) (id = 1, name = DEF)
13Jan2013 : (id = 0, name = PQR) (id = 1, name = XYZ)
You can use a for loop.
for (var i in json) {
...
}
Then, i is the current key, so, you can acess json[ i ] and get the data to the corresponding index.
And then, if you need to iterate over inner elements, you can do the same thing.
You can use for ... in but you should combine it with hasOwnProperty or you'll find yourself iterating over inherited properties likely breaking your code.
for (var key in object) {
if (object.hasOwnProperty(key)) {
// Do stuff.
}
}
I wrote a recursive function that traverses nested DOM nodes of the following form:
<a href="#" title="test">
<div id="nested-image">
<img src="image.jpg" />
</div>
</a>
The recursive function is the following:
function getNestedNodes(nodeList) {
var ary = [];
for(var i = 0; i < nodeList.length; ++i) {
var myJSONChildren = {};
if(nodeList[i].childElementCount) {
var htmlCollection = nodeList[i].children;
for(var j = 0; j < htmlCollection.length; ++j) {
for(var k =0, attrs = htmlCollection[j].attributes, l = attrs.length; k < l; ++k) {
myJSONChildren['tag'] = htmlCollection[j].nodeName;
myJSONChildren[attrs.item(k).nodeName] = attrs.item(k).nodeValue;
};
}
myJSONChildren['children'] = getNestedNodes(htmlCollection);
ary.push(myJSONChildren);
};
}
return ary;
}
so if I call that function this way:
var links = document.querySelectorAll('a');
console.log(JSON.stringify(getNestedNodes(links)));
it should return a JSON array of the following form:
[{
tag:'a',
href:"#",
title:"test",
children:[{
tag:"div",
id:"nested-image",
children:[{
tag:"img",
src:"image.jpg"
}]
}]
}]
}]
However, it is only returning one of the following form:
[{
"tag":"DIV",
"id":"nested-image",
"children":[{
"tag":"IMG",
"src":"https://www.gravatar.com/avatar/d1a336ae4b6876a4c5c044ec17876ce0",
"children":[]
}]
}]
and I haven't been able to get the form that I want in a proper way without getting empty results, or duplicate results.
Also, I'd like to optimize my recursive function, I'm sure that I can be refactored into something more readable.
Here's a fiddle for you to see:
http://jsfiddle.net/DfHqv/
Any help will be greatly appreciated!
The problem is that you've made your function to anticipate receiving a collection, yet you're looping two node collections within.
So it seems that you're not pushing in the nodes from the outer loop, but only the children. This would explain why you're not getting the top level.
Just keep it to a single loop of nodes (and then the one for attributes, of course), and then instead of looping the children within a new loop, just pass it in the recursive call.
function getNestedNodes(nodeList) {
var ary = [];
// Loop the collection of nodes
for(var i = 0; i < nodeList.length; ++i) {
var node = nodeList[i];
// Create the new object with the "tag" populated
var jsonNode = {"tag":node.nodeName};
// Add the attributes to the object
for(var k =0, attrs = node.attributes, l = attrs.length; k < l; ++k) {
jsonNode[attrs.item(k).nodeName] = attrs.item(k).nodeValue;
}
// Make a recursive call if any children are present, and add the result
if (node.children && node.children.length)
jsonNode['children'] = getNestedNodes(node.children);
ary.push(jsonNode);
}
return ary;
}
DEMO: http://jsfiddle.net/argA3/1/
[
{
"tag": "A",
"title": "test",
"href": "#",
"children": [
{
"tag": "DIV",
"id": "nested-image",
"children": [
{
"tag": "IMG",
"src": "image.jpg"
}
]
}
]
}
]
This seems to work:
function getNestedNodes(nodeList) {
var ary = [];
for (var i = 0; i < nodeList.length; i += 1) {
var attributes = {};
for (var key in nodeList[i].attributes) {
attributes[nodeList[i].attributes.item(key).nodeName] = nodeList[i].attributes.item(key).nodeValue;
}
ary.push({
tag: nodeList[i].nodeName,
attributes: attributes,
children: getNestedNodes(nodeList[i].children)
});
}
return ary;
}
var links = document.querySelectorAll('a');
console.log(JSON.stringify(getNestedNodes(links)));
Output:
[{"tag":"A","attributes":{"href":"#","title":"test"},"children":[{"tag":"DIV","attributes":{"id":"nested-image"},"children":[{"tag":"IMG","attributes":{"src":"https://www.gravatar.com/avatar/d1a336ae4b6876a4c5c044ec17876ce0?s=32&d=identicon&r=PG"},"children":[]}]}]}]
Since we're all prividing various (refactored) bids:
// getNestedNodes2(nodeList)
// #nodeList: a collection of nodes to serialize
function getNestedNodes2(nodeList){
// iterate over the node collection
for (var i = 0, result = []; i < nodeList.length; i++){
// begin building a definition of the current node
var thisNode = {
tag: nodeList[i].tagName
};
// iterate over any attributes on the current node and add them
// to the current definition.
for (var j = 0, attributes = nodeList[i].attributes; j < attributes.length; j++){
thisNode[attributes.item(j).nodeName] = attributes.item(j).nodeValue;
}
// check for child elements and, if present, also add them to
// the definition
if (nodeList[i].childElementCount > 0){
thisNode.children = getNestedNodes2(nodeList[i].children);
}
// add the definition to the results set
result.push(thisNode);
}
// return the results
return result;
}
and the end result:
[
{
"tag": "A",
"title": "test",
"href": "#",
"children": [
{
"tag": "DIV",
"id": "nested-image",
"children": [
{
"tag": "IMG",
"src": "https://www.gravatar.com/avatar/d1a336ae4b6876a4c5c044ec17876ce0?s=32&d=identicon&r=PG"
}
]
}
]
}
]
Keep in mind you're accepting a collection in, which means the nodes in that first call are ignored when you go right in to iterating over them and only building a definition of the children. Instead, work on the nodes within the received collection first, then have recursion take care of the children.
I have this JS object:
{
"data": {
"nid": [{
"cid": "32",
"uid": "780",
"comment": "text"
}]
},
"request_status": "found"
}
how can I loop through these items to get comment value ("comment":"text")?
You don't really need to loop to get it. Just do...
var obj = {"data":{"nid":[{"cid":"32","uid":"780","comment":"text"}]},"request_status":"found"};
var text = obj.data.nid[0].comment;
Or if there are several, you can use forEach...
obj.data.nid.forEach(function(val,i) {
alert( val.comment );
});
Or a traditional for loop...
for( var i = 0; i < obj.data.nid.length; i++ ) {
alert( obj.data.nid[i].comment );
}
Or if you want to build an Array, use map...
var arr = obj.data.nid.map(function(val,i) {
return val.comment;
});
Or again a traditional for loop...
var arr = []
for( var i = 0; i < obj.data.nid.length; i++ ) {
arr.push( obj.data.nid[i].comment );
}
Given:
var obj = {
"data": {
"nid": [{
"cid": "32",
"uid": "780",
"comment": "text"
}]
},
"request_status": "found"
};
The direct way to retrieve the comment is:
obj["data"]["nid"][0]["comment"]
// or
obj.data.nid[0].comment
As far as "looping" through the items to get the value, I'm not sure how a loop makes sense. Are you saying you might not know the structure of the object but you know it will have a "comment" field in there somewhere?
The "nid" array only has one item in it - if this was just a sample but really you'll have an array with more values you can loop through that array:
var nid = obj["data"]["nid"], // get a direct reference to the array to save
i; // repeating obj.data.nid everywhere
for (i=0; i < nid.length; i++) {
// do something with the comment in the current item
console.log(nid[i]["comment"]);
}
If you're just referring to that specific object (or if every object you are working with follows that same pattern), then you can just access the value directly:
var theObj = {"data":{"nid":[{"cid":"32","uid":"780","comment":"text"}]},"request_status":"found"};
alert(theObj.data.nid[0].comment);
If you want to do something iterative, then perhaps try this:
var theObj = {"data":{"nid":[{"cid":"32","uid":"780","comment":"text"}]},"request_status":"found"};
for (var index = 0; index < theObj.data.nid.length; index++) {
var item = theObj.data.nid[index];
if (item.comment) {
alert(item.comment);
}
}
Or if you really want to do the entire thing iteratively:
window.searchObj = function(theObj) {
if (theObj.comment) {
alert(theObj.comment);
}
if (theObj instanceof Array) {
searchArray (theObj);
}
else if (theObj instanceof Object) {
for (var key in theObj) {
searchObj(theObj[key]);
}
}
};
window.searchArray = function(theArray) {
for (var index = 0; index < theArray.length; index++) {
var item = theArray[index];
searchObj(item);
}
};
var theObj = {"data":{"nid":[{"cid":"32","uid":"780","comment":"text"}]},"request_status":"found"};
searchObj(theObj);
I need to find out if an id occurs in my JSON object, for example:
{
"requested": "2009-07-25T14:12:25+01:00",
"channels": [
{"id": 1, "name": "General", "created": "2009-07-25 14:00:02"}
]
}
Specifically I need to check if my id (say, 2) occurs in channels.i.id. How can this be done?
Try this:
var id = 2,
found = false;
for (var i=0; i<channels.length; i++) {
if (channels[i].id == id) {
found = true;
break;
}
}
Or more succinctly and probably faster :
var id = 2;
for (var found, i = channels.length; i && !(found = channels[--i].id === id);)
;