sorry I feel this is sort of a stupid question I have searched quite a bit and I cannot find my answer.
I have an array in JavaScript that I am inserting a bunch of elements. The trouble is I cannot then get the values of the elements back out, I think I am getting the property of the actual array. Below is what I am doing and what I am trying to do. Thanks in advance for the help. This is not the full traverse method, it actually does go through a bunch of times. When I previously just had an associative array items[a] it worked perfectly.
var element = { html: "", group: "" };
var array = [];
function traverse(o) {
for (var key in o) {
element.html = "<li class='item'>" + key + " : </li>";
element.group = b;
array.push(element);
}
}
I want to print the html from each element, the issue is I get the .html from only the first element each time.
function printElements() {
for (item in array) {
var element = array.pop();
console.log(element.html);
}
}
I also tried.
function printElements() {
for (item in array) {
console.log(array.html);
}
}
I want to keep the array intact, I do not want to pop and elements I just want to print them.
The main problem isn't to get the data out of the array, it never gets into the array in the first place.
You don't have a bunch of elements in the array, you only have one element that you change and add to the array over and over. When you put it in the array it's not copied, it's just the reference to the element that is placed in the array. You end up with an array full of references to the same single element.
Create a new element for each iteration in the loop when you populate it:
for (var key in o) {
var element = {};
element.html = "<li class='item'>" + key + " : </li>";
element.group = b;
array.push(element);
}
Use a simple for loop instead:
for (var i = 0; i < array.length; i++) {
var item = array[i];
// do stuff
}
It is unadvisable to use the nicer for loop syntaxes on arrays in JavaScript because they will iterate through all key/value pairs in the array, not just the array numeric keys. This is because arrays are objects, too, and the for...in loop syntax does not differentiate between them.
You're not using the iterated object, instead you are using array... change this:
function printElements() {
for (item in array) {
console.log(array.html);
}
}
to this:
function printElements() {
for (item in array) {
console.log(array[item].html);
}
}
jsfiddle
Do it this way:
var array = [];
function traverse(o) {
for (var key in o) {
var b = 'b'; // if that is what you have ment
var element = { html : "<li class='item'>" + key + " : </li>", group : b};
array.push(element);
}
}
function printElements() {
for (var item=0; item<array.length; item++) {
console.log(array[item].html);
}
}
That's because it isn't safe to use for each in case of arrays and you should have new object for each array element.
Be sure not to use delete on array elements either.
Related
I have an array of objects.
ABC.getAggregation("V")[0].getItems();
this produces the result:
MY ARRAY OF OBJECTS
In the console i can get the result i am looking for by specifying the position of the item like this:
ABC.getAggregation("V")[0].getItems()[0].getPosition()
ABC.getAggregation("V")[0].getItems()[1].getPosition()
ABC.getAggregation("V")[0].getItems()[2].getPosition()
The result of the above code produces string values e.g "3.4554,43,0".
How can i loop through each item and get the position in my code. just like the above code that i typed in the console. there wont always be 3 objects this is why i cant hard code the above 3 lines.
Try using a the Array.prototype.forEach() function. The function will be called for each element in the array, passing in the element as the first parameter.
ABC.getAggregation("V")[0].getItems().forEach( function (item) {
item.getPosition();
//do something else
});
More on ".forEach()"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
You can treat it like any other array:
var myArray = ABC.getAggregation("V")[0].getItems();
for(var i=0; i< myArray.length; i++){
myArray[i].getPosition(); //Do something with the position.
}
You can use for loop to iterate trough all of them.
for(var i=0; i<ABC.getAggregation("V").getItems().length; i++) {
ABC.getAggregation("V")[0].getItems()[i].getPosition();
}
You can use forEach loop to iterate trough all of them.
ABC.getAggregation("V").getItems().forEach (item, index) {
return ABC.getAggregation("V")[0].getItems()[index].getPosition();
}
A very simple way to iterate through each object in the array is just with a for loop on the array, you don't even need to declare your iterating variable.
ex:
var anArray = ['one', 'two', 'three'];
for( i in anArray){
console.log('index #: ' + i );
console.log(anArray[i]);
}
will print out all the elements in anArray:
index #: 0
one
index #: 1
two
index #: 2
three
!! Apparently this is a good example of how not to do it :P
You can assign the items to an array and loop through them like this:
var items = ABC.getAggregation("V")[0].getItems();
var returnString = "";
for (var key in items ) {
if (items .hasOwnProperty(key)) {
var element = items [key];
returnString += element.getPosition() + ',';
}
}
returnString = returnString.substring(0, x.length-1);
console.log(returnString);
I have this object:
key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
And I have an array with only types and I need to add the given image to it, the array looks something like this:
[{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}]
Basically I want to loop the array, find the type in the key object and get the given image and save it into the array.
Is there any simple way to do this?
One thing that stands out here for me is the line
...get the given image and save it into the array
I'm assuming this means the original array. I think a better approach would be to map the appropriate keys and values to a new array but I've assumed, for this example, that it's a requirement.
In an attempt to keep the solution as terse as possible and the request for a lodash solution:
_.each(key, function(prop){
_.each(_.filter(types, { type: prop.type }), function(type) { type.image = prop.img });
});
Given the object of keys and an array of objects like so:
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var arr = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
We can first create an array of the properties in the object key to make iterating it simpler.
Then loop over the array arr, and upon each member, check with a some loop which image belongs to the member by its type (some returning on the first true and ending the loop).
You can change the forEach to a map (and assign the returned new array to arr or a new variable) if you want the loop to be without side-effects, and not to mutate the original array.
var keyTypes = Object.keys(key);
arr.forEach(function (item) {
keyTypes.some(function (keyType) {
if (key[keyType].type === item.type) {
item.image = key[keyType].img;
return true;
}
return false;
});
});
The smarter thing would be to change the object of the imagetypes so that you could use the type as the accessing property, or create another object for that (as pointed out in another answer).
I'm not sure if this solution is modern, but it does not use any loops or recursion.
object = {
spawn: {type:1, img:app.assets.get('assets/spawn.svg')},
wall: {type:2, img:app.assets.get('assets/wall.svg')},
grass: {type:3, img:app.assets.get('assets/grass.svg')},
spike: {type:4, img:app.assets.get('assets/spike.svg')},
ground: {type:5, img:app.assets.get('assets/ground.svg')}
};
arr = [
{type:1, image:null},
{type:3, image:null},
{type:2, image:null},
{type:2, image:null},
{type:5, image:null}
];
var typeImages = {};
Object.getOwnPropertyNames(object).forEach(function(value){
typeImages[object[value].type] = object[value].img;
});
arr = arr.map(function(value){
return {
type: value.type,
image: typeImages[value.type]
};
});
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var typesArray = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
for(var i = 0, j = typesArray.length; i < j; i++)
{
typesArray[i].image = getKeyObjectFromType(typesArray[i].type).img;
}
function getKeyObjectFromType(type)
{
for(var k in key)
{
if(key[k].type == type)
{
return key[k];
}
}
return {};
}
for (var i = 0; i < typesArray.length; i++) {
for (prop in key) {
if (key[prop].type === typesArray[i].type) {
typesArray[i].image = key[prop].img;
}
}
}
It loops through the array ("typesArray"), and for each array item, it go through all the objects in key looking for the one with the same "type". When it finds it, it takes that key object's "img" and saves into the array.
Using lodash (https://lodash.com/):
var key = {
spawn:{type:1,img:app.assets.get('assets/spawn.svg')},
wall:{type:2,img:app.assets.get('assets/wall.svg')},
grass:{type:3,img:app.assets.get('assets/grass.svg')},
spike:{type:4,img:app.assets.get('assets/spike.svg')},
ground:{type:5,img:app.assets.get('assets/ground.svg')}
};
var initialList = [{type:1,image:null},{type:3,image:null},{type:2,image:null},{type:2,image:null},{type:5,image:null}];
var updatedList = _.transform(initialList, function(result, item) {
item.image = _.find(key, _.matchesProperty('type', item.type)).img;
result.push(item);
});
This will go over every item in the initialList, find the object that matched their type property in key and put it in the image property.
The end result will be in updatedList
I currently have a list of objects in javascript indexed by a key:
var list = [];
list['a'] = [];
list['a'].push({obj: 'test'});
list['a'].push({obj: 'test2'});
list['b'] = [];
list['b'].push({obj: 'test'});
list['b'].push({obj: 'test2'});
I would list to remove the entry based on the key (a/b)
I have tried the following:
for(var x in list) { delete list[x]; }
that works but it actually leaves an undefined entry in the list.
I have also tried splicing the array, but that does not seems to work in this case.
Any thoughts on how to remove the entry in javascript or jQuery?
Thanks.
The Fix:
After reading some of the comments, i was able to better understand what my list is consistent of. Therefor, i was able to do the removal by doing the following:
delete list.b;
I'm not sure if my list is best way to organize my structure, but doing a delete on the list and treating it like an object property did the trick.
Thanks for all the feedback.
I'll assume list is an object, not an array.
If you want to reset a or (or b it's done the same way)
list.a.length = 0;
If you want to delete an element from a at a known index (let index)
list.a.splice(index, 1);
You're attempting to add the elements to the array object as object properties and not as array elements. You can verify this by inspecting the value of list.length (will be 0).
So when doing something such as the following:
function removeProperty(id) {
if (list.hasOwnProperty(id)) {
delete list[id];
}
}
removeProperty('a');
it's really the same as:
delete list.a;
which is why you think it leaves an undefined 'entry' in the 'list'.
You'll need to use a literal object instead:
var list = {};
list['a'] = [];
...
list['b' = [];
...
which would allow you to use delete and have it behave as you expect. Of course you'll lose the .length property on the array but you never had that anyway.
Create a simple prototype for the Array class
Array.prototype.remove = function() {
// Helper function to remove a single element from a list if exists
item = arguments[0]
if (this.includes(item)) {
index = this.indexOf(item)
this.splice(index, 1)
}
}
// Now we can call
myList.remove(YourObject)
The above code will add the remove method to all your lists, so this will help you not just for objects but also strings, integers, or any data type
var list = {1: [{},{}], 2: [{},{}]};
function removeProperty(obj, prop){
if(obj[prop]){
delete obj[prop];
}
}
removeProperty(list,"1");
console.log(list);
If this quote:
I would list to remove the entry based on the key (a/b)
means you would like to select the list to consider based off the key (a/b), then remove elements in the list (or all of them), you can try this:
var list = [];
list['a'] = [];
list['a'].push({obj: 'test4'});
list['a'].push({obj: 'test5'});
list['b'] = [];
list['b'].push({obj: 'test'});
list['b'].push({obj: 'test2'});
var toRemove = 'test4';
var removeFrom = "a";
var consideredList;
for (var prop in list) {
if (prop == removeFrom) {
consideredList = list[prop];
}
}
//Remove everything from the considered list
consideredList.splice(0, consideredList.length);
//Remove based off value, if you know the property name
// for(var pos in consideredList) {
// if(consideredList[pos].obj == toRemove) {
// consideredList.splice(pos, 1);
// }
// }
I made a Plunker of a few different cases (check the script.js file). There seems to be a bit of confusion on what you are after and hopefully this is helpful to you somehow. Good luck.
I'm adding a bunch of input fields into an associative array. I can access the individual elements fine, eg. this works:
arr = new Array();
field = document.getElementById("someField");
arr[field] = someValue;
alert(arr[field].id);
But when I try to loop over them, the id shows up as undefined, and only one element is looped over.
for (var elem in arr) {
alert(elem.id + " " + arr[elem]);
}
Am I looping over it wrong?
Edit: arr.length shows up as 0 for some reason even though I'm able to access its elements.
the key in a javascript-array has to be a number or string.
field is automatically converted to a string with toString().
arr = new Array();
field = document.getElementById("someField");
var key = field.toString();
arr[key] = someValue;
alert(arr[key].id);
in your for-loop, you iterate the keys of that array.
field.toString() in that case.
and a string does not have a id-property.
this will work:
for (var elem in arr) {
alert(arr[elem].id + " " + arr[elem]);
}
by the way toString() of a DOM-Element ist often a generic string like "[SpanElement]".
if you try to add multiple span-elements, you're effectivle overriding the item with "[SpanElement]" as key and end up with just one element.
in respect to #user2736012 comments, i encourage everyone to read
"JavaScript Associative Arrays Demystified"
Any associative array in JavaScript is an object. Arrays are objects that have special methods because they are numerically indexed. So your code should look something like this:
obj = {};
field = document.getElementById("someField");
obj[field] = someValue;
for (var p in obj) {
alert(obj[p].id);
}
I have built an object in PHP, used JSON_encode function and send it as a JSON string to my JS script via ajax. Then I convert it back to an object. The problem I am having is that I wanted to keep the object in the order that it was originally created in. Please see this picture of what the object looks like once I get it into JS:
When I created the object, it was sorted by the customer field alphabetically. The customer name starting with A would come first, B second, etc. As you can see, now, the first element of the object as customer starting with S. It looks like somehow it got automatically sorted by the key of the top-level object, which is an integer, so I understand why this happened.
So i want to do is re-sort this object so that all the sub-objects are sorted by the customer field alphabetically. Is this possible? If so, how do I do it?
Thanks!
I've changed Fabricio Matée answer to become more flexible and return the sorted object.
function alphabetical_sort_object_of_objects(data, attr) {
var arr = [];
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
var obj = {};
obj[prop] = data[prop];
obj.tempSortName = data[prop][attr].toLowerCase();
arr.push(obj);
}
}
arr.sort(function(a, b) {
var at = a.tempSortName,
bt = b.tempSortName;
return at > bt ? 1 : ( at < bt ? -1 : 0 );
});
var result = [];
for (var i=0, l=arr.length; i<l; i++) {
var obj = arr[i];
delete obj.tempSortName;
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var id = prop;
}
}
var item = obj[id];
result.push(item);
}
return result;
}
Then just call the function like this
your_object = alphabetical_sort_object_of_objects(your_object, 'attribute_to_sort');
It's probably the difference between a JavaScript Object and a JavaScript Array. Objects are more like hash tables, where the keys aren't sorted in any particular order, whereas Arrays are linear collections of values.
In your back end, make sure you're encoding an array, rather than an object. Check the final encoded JSON, and if your collection of objects is surrounded by {} instead of [], it's being encoded as an object instead of an array.
You may run into a problem since it looks like you're trying to access the objects by an ID number, and that's the index you want those objects to occupy in the final array, which presents another problem, because you probably don't want an array with 40,000 entries when you're only storing a small amount of values.
If you just want to iterate through the objects, you should make sure you're encoding an array instead of an object. If you want to access the objects by specific ID, you'll probably have to sort the objects client-side (i.e. have the object from the JSON response, and then create another array and sort those objects into it, so you can have the sorted objects and still be able to access them by id).
You can find efficient sorting algorithms (or use the one below from ELCas) easily via Google.
Here's a generic iteration function which pushes all objects into an array and sorts them by their customer property in a case-insensitive manner, then iterates over the sorted array:
function iterate(data) {
var arr = [];
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
var obj = {};
obj[prop] = data[prop];
obj.tempSortName = data[prop].customer.toLowerCase();
arr.push(obj);
}
}
arr.sort(function(a, b) {
var at = a.tempSortName,
bt = b.tempSortName;
return at > bt ? 1 : ( at < bt ? -1 : 0 );
});
for (var i = 0, l = arr.length; i < l; i++) {
var obj = arr[i];
delete obj.tempSortName;
console.log(obj);
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var id = prop; //gets the obj "index" (id?)
}
}
console.log(id);
var item = obj[id];
console.log(item.customer);
//do stuff with item
}
}
Fiddle
sortObject(object){
if(typeof object === 'object'){
if(object instanceof Date){
return object;
}
if(object instanceof Array){
return object.map(element => this.sortObject(element));
} else {
return Object.keys(object).sort().reduce((result, key) => {
if(object[key] && object[key] !== null) {
result[key] = this.sortObject(object[key]);
}
return result;
}, {});
}
}
return object;
}