I have a situation where i add tables on a click of button and each table is stored in array. Now when i remove 2 or 3 tables, wrong index are being removed.
addTable: function (obj) {
for (var i = 0; i < obj.length; i++) {
// Adding of table
array.push(obj)
// delete code of the table
(function (i) {
deleteButton.addEventListener('click', function (e) {
array.splice(i, 1);
});
})(i);
}
}
The problem i am facing is the value of i is always zero. each time i click on the button a the addTable function is called and the counter is always zero and that is passed to the function(i) too.
Any ideas on how can keep track of different i or counter so that it deletes the correct index in the array
Here is an update
this is the sample object i am sending each time.
Each time i click on the Add Table button, the same object is being passed. Now i am having difficulty in keeping track of the index of each item.
Once you've removed one table, all other tables have moved and their indexes that you installed in the delete Buttons will be wrong now. When you remove items from the array, all indexes shift.
So, suppose you remove table 3. Then, you press delete for table 4. It's got an index of 4, but since you already removed table 3, it's in spot 3 in the array now (after the previous delete), not spot 4. But, you're code still has i==4 associated with that table and is trying to delete it here, but it's not there any more.
What you are doing is just not a good way to do this. If you want to expand further on what you're really trying to do, we can help with much better solutions.
Given the limited info we have so far, all I know of to do is to find the item in the array (wherever it might have moved to) and delete it from there.
addTable: function (obj) {
for (var i = 0; i < obj.length; i++) {
// Adding of table
array.push(obj)
// delete code of the table
(function (item) {
deleteButton.addEventListener('click', function (e) {
// search through the array to find where this item is
// and remove it from the array
for (var j = 0; j < array.length; j++) {
if (array[j] === item) {
array.splice(j, 1); // remove it
break;
}
}
});
})(obj);
}
}
I do not know about deleteButton, but in case that obj is array with only one element (length equals 1): [{....}] and array.push is native Array.prototype.push method then:
addTable: function (obj) {
// Adding of table
var index=array.push(obj);
// delete code of the table
deleteButton.addEventListener('click', function (e) { array.splice(index, 1); });
}
if obj.length is undefined i will allways be 0
further more, then i < obj.length return false and the for loop will never execute
if obj passed in is this object:
var addObjectResponse = [{...}];
then addObjectResponse is an array of 1, hence i will allways be 0
i = 0
obj.length = 1
i < obj.length => 0 < 1 => true once
Related
I am trying to delete objects from my array via javascript. Im building a simple mobile jquery application and want to delete items from an array. I use the following code. I have a list with checkboxes in it. Every checkbox has a value that belongs to the list item. So when multiple checkboxes are checked.. it should delete all these objects (items) from the array.
function deleteFunction()
{
objects = getObjects();
$("input:checked").each(function()
{
var inputValue = $(this).val();
for(i = getObjects().length; i >=0; i--)
{
if('{"title":"'+ inputValue + '"}' == JSON.stringify(objects[i]))
{
objects.splice(i, 1);
return true;
}
}
});
alert(JSON.stringify(objects));
window.location.reload();
}
The annoying thing is as follows:
When i slice the object from the array, the object is restored on the second iteration. So it always removes only 1 object from the array.
To test my output i used the following code within the if statement:
alert(i);
alert(JSON.stringify(objects[i]));
objects.splice(i, 1);
alert(i);
alert(JSON.stringify(objects));
return true;
The output is as follows
1
{"title":"hi2"}
1
[{"title":"hi1"}, {"title":"hi3"}]
2
{"title":"hi3"}
2
[{"title":"hi1"}, {"title":"hi2"}]
so i slice hi2, but has returned
Thanx for answer and respond
Solution Thanx to depperm + indubitablee:
function deleteFunction()
{
var objects = getObjects();
$("input:checked").each(function()
{
var inputValue = $(this).val();
for(i = objects.length -1; i >=0; i--)
{
if(objects[i].title == inputValue)
{
objects.splice(i, 1);
}
}
});
localStorage.setItem("objects", JSON.stringify(objects));
window.location.reload();
}
There are a few things I would change, first in the for loop no need to call getObjects() each time just use objects. Then in the if simply check if the objects[i].title is the same as the inputValue.
function deleteFunction()
{
objects = getObjects();
$("input:checked").each(function()
{
var inputValue = $(this).val();
for(i = objects .length; i >=0; i--)
{
if(objects[i].title==inputValue)
{
objects.splice(i, 1);
}
}
});
alert(JSON.stringify(objects));
window.location.reload();
}
use .splice() instead of .slice().
slice does NOT alter/manipulate the original array at all, it just creates another array based on your selection.
splice does alter the original array.
reference: http://www.devcurry.com/2010/12/slice-and-splice-in-javascript.html
The array method slice does not remove array elements. Use splice instead.
There are some problems with your code:
You missed the keyword var sometimes.
The variable i is equal to the length of the array in the first iteration. It should be one minus that.
Instead of converting to JSON to compare the objects, you could have just compared the value of the title property.
I have an array items. I need to make sure that in the current iteration of the loop I can safely call the next item of the array
for(var i = 0; i < items.length; ++i) {
// do some stuff with current index e.g....
item = items[i];
// then do something with item # i+1
if(items[i+1]) {
//do stuff
}
}
Is this how it is done or if not how/what would be the better way?
P.S. I do not want to do a bound check
If you want to loop through every element except the last one (which doesn't have an element after it), you should do as suggested:
for(var i = 0; i < items.length-1; ++i) {
// items[i+1] will always exist inside this loop
}
If, however, you want to loop through every element -even the last one-, and just add a condition if there is an element after, just move that same condition inside your loop:
for(var i = 0; i < items.length; ++i) {
// do stuff on every element
if(i < items.length-1){
// items[i+1] will always exist inside this condition
}
}
if(items[i+1]) will return false (and not execute the condition) if the next element contains a falsey value like false, 0, "" (an empty String returns false).
Put a value check on variable i and make sure it is less than items.length-1 in order to safely access items[i+1].
for(var i = 0; i < items.length-1; ++i) {
if(items[i+1]) {
//do stuff
}
}
Drop the for loop and use array#forEach, and simply check whether a next value exists:
items.forEach(function (item, index) {
if (!items[index + 1]) return;
// do something with item and items[index + 1]
});
I have an array rosters and i want to alter this array according to some conditions. Here what I'm trying to do.
somefunction(callback) {
for (var i in this.rosters) {
var roster = this.rosters[i];
if (roster.age > 7200) {
this.rosters.splice(i, 1);
} else {
this.rosters[i].age = this.EMarshal.tu.getAgeOfTime(
this.EMarshal.tu.getMyTime(
this.EMarshal.tu.getMyDate(roster.date), roster.shifttime
)
);
console.log(this.rosters[i].age);
}
}
callback();
}
When the the if condition is true and splice is been called, control comes out of from loop and call callback(). But i want to run the loop for each values in the array.
plz carefully notice that there are rosters and roster 2 different variables.
Any idea why its happening and the solution will be usefull.
Thanks
It's just because you are trying to alter the array on which you are iterating.
So, just ad some logic to store the indexes as you have said you have tried.
Here is one suggestion
before getting into loop var index = [];
then your if condition
if (roster.age > 7200) {
index.push(i);
}
and then after the loop, remove those indexes from rosters
for (var j = index.length - 1; j > -1; j-- ) {
console.log(j);
this.rosters.splice(index[j], 1);
}
Remember to iterate the index from last index otherwise you will remove the 1st index and the trying to remove the last index from the rosters, but now you have removed the element from the array so the length is been changed.
I have an empty array (called zoomthumbsarray) which gets values pushed to it whilst a 'for' loop is running. This 'for' loop is checking if a thumbnail image is present in the backend against the particular product the user is viewing. If there is an image it gets added into a vertical slider. The current issue is there are non colour specific images (like lifestyle shots) that are being added into the slider multiple times.
So I need to check if the image found in the for loop is currently stored in the array. If it is present, the image has already been generated and I don't want it to get pulled into the slider again. If it hasn't then the image will get added.
Below is the code I am working on. I would presume indexOf would be used but can't get this to work.
Any help would be really appreciated.
var zoomthumbsarray = [] // Empty array which gets populated by .push below during loop
for (var i = 0; i < storeImgsArr.length; i++) { // storeImgsArr finds the quantity of attributes present against the product. This loops and increments counter if there is another attibute image
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) { // Loop and increment counter if there is a Large image
zoomthumbsarray.push(storeImgsArr[i].images.imgS[e].slice(-16)); // Slices off last 16 characters of image path i.e. _navy_xsmall.jpg or 46983_xsalt1.jpg and pushes this into 'zoomthumbsarray' array
// if statement sits here to build the html to add the image to the slider
}
}
zoomthumbsarray = [] // Resets array to zero
ANSWER
As answered by Chris I used $.unique to only keep unique values in the array.
Then wrap an if statement around the code to build the thumb image html if the array === 0 or if the current image isn't already in the array.
Updated code below:
var zoomthumbsarray = [] // Empty array which gets populated by .push below during loop
for (var i = 0; i < storeImgsArr.length; i++) { // storeImgsArr finds the quantity of attributes present against the product. This loops and increments counter if there is another attibute image
if (zoomthumbsarray === 0 || zoomthumbsarray.indexOf(storeImgsArr[i].images.imgS[e].slice(-16)) < 0) { // If statement is true if array === 0 or if the current image isn't already in the array
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) { // Loop and increment counter if there is a Large image
zoomthumbsarray.push(storeImgsArr[i].images.imgS[e].slice(-16)); // Slices off last 16 characters of image path i.e. _navy_xsmall.jpg or 46983_xsalt1.jpg and pushes this into 'zoomthumbsarray' array
zoomthumbsarray = $.unique(zoomthumbsarray); //Keeps only unique elements
// if statement sits here to build the html to add the image to the slider
}
}
}
zoomthumbsarray = [] // Resets array to zero
Some cheap and dirty ideas:
Using underscore/lodash:
zoomthumbsarray = _.uniq(zoomthumbsarray); //Keeps only unique elements
jQuery has one as well:
zoomthumbsarray = $.unique(zoomthumbsarray); //Keeps only unique elements
then you loop through the array and build HTML.
Update:
There's something a bit odd about the rest of the JS. Might this work (if you're using a new enough browser)?
var zoomthumbsarray = [];
storeImgsArr
.map(function(item) { return item.images.imgS; })
.forEach(function(imgS) {
zoomthumbsarray = zoomthumbsarray.concat(imgS.map(function(imagePath) {
return imagePath.slice(-16);
}));
});
zoomthumbsarray = $.unique(zoomthumbsarray);
I have tried indexOf (see first if statement below) but this doesn't work.
As #elclanrs said, indexOf does return the index in the array not a boolean. You only will need to see if it's >= 0 to test whether an image is already contained in the array.
var zoomthumbsarray = [];
for (var i = 0; i < storeImgsArr.length; i++) {
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) {
var image = storeImgsArr[i].images.imgS[e].slice(-16);
if (zoomthumbsarray.indexOf(image) < 0) { // not yet in the array
zoomthumbsarray.push();
// and build the html to add the image to the slider
}
}
}
If you have really lots of images and notice this starts slowing the page down, then there are too many images in your page anyway. No, joke aside; …then check the optimisation by #Ivey.
instead of using an array you can use an object to store the images as keys and a dummy value (possibly true). then you can extract the keys from this object.
var images = {};
for (var i = 0; i < storeImgsArr.length; i++) {
for (var e = 0; e < storeImgsArr[i].images.imgL.length; e++) {
images[storeImgsArr[i].images.imgS[e].slice(-16))] = true;
}
}
var zoomthumbsarray = [];
for(var k in images) {
zoomthumbsarray.push(k);
// build the html to add the image to the slider
}
EDIT: Added build html comment
Hi I have an array that hold the following numbers, however when I loop though the eachNode function(which iterates 13 times) it repeats all the list elements 13 times. I tested everything but it still produces an error, I'm I executing the for loop correctly?
list[61,67,78]
var len = list.length;
fd.graph.eachNode(function (node) { // loops thru all node id's in graph (13)
for (var i = 0; i < len; ++i) {
if (i in list) {
var nody = list[i]; // I put the number in a variable
var nodess = fd.graph.getNode(nody); //this takes the number and matches it with a node id, it "odjectify" it
if (node.id != nodess.id) { // if the list nodes are not the same
node.setData('alpha', 0); //
node.eachAdjacency(function (adj) { // this make the unmatched nodes disappear
adj.setData('alpha', 0, 'end');
});
}
}
}
});
This line is unneeded:
if (i in list)
The in keyword returns true if its right operand contains the property specified by its left operand. When using this with arrays, it returns unexpected results. The behavior of this keyword is insignificant in this context, so you should simply take it out.
Moreover, you need to create the list array like this:
var list = [61, 67, 78];
...however, when I loop though eachNode (which iterates 13 times) it repeats all the list elements 13 times
It doesn't, it in fact iterates over eachNode 13 times. You also made a for loop which will traverse the list array by its length.
Now that you've given me more detail as to what you want, here is the updated code. I hope it works for you:
fd.graph.eachNode(function (node) {
var flag = false;
for (var i = 0; i < len; ++i)
{
var nody = list[i];
var nodess = fd.graph.getNode(nody);
if (node.id == nodess.id) {
flag = true; break;
}
}
if (flag)
{
node.setData('alpha', 0);
node.eachAdjacency(function (adj) {
adj.setData('alpha', 0, 'end');
});
}
});
This is the behavior by design:
You loop over the graph (13 times as you say), then inside each iteration you loop over your array (3 items).
If you only want to loop once over your array, just move it out of the outer loop