Delete elements with a particular class name (using javascript)? - javascript

I was trying to delete elements with a particular class name, but it doesnt work. Any idea why?
function delete_elems(){
var my_elems = document.getElementsByClassName("my_elem");
for(k=0; k<my_elems.length; k++){
my_elems[k].parentElement.removeChild(my_elems[k]);
}
}
I also tried:
function delete_elems(parentElem){
var my_elems = document.getElementsByClassName("my_elem");
for(k=0; k<my_elems.length; k++){
parentElem.removeChild(my_elems[k]);
}
}

Begin at the end:
for(k=my_elems.length-1;k>=0; --k)
http://jsfiddle.net/doktormolle/fDNqq/

The getElementsByClassName method returns a live node list, so iterating over it using an index and at the same time modifying the list (by removing nodes from the document) means that as elements are removed, the list is modified so what started as a list with 10 members will only have 9 once one is removed. If you remove item 0, then all items are re-indexed so what was item 1 is now 0, 2 is 1 and so on up to 8 (since there are only 9 left).
As noted by Dr. Molle, you may be able to avoid this issue by iterating over the list from the end.
You can avoid a counter altogether:
var el;
while ((el = my_elems[0])) {
el.parentNode.removeChild(el);
}
Note that when using a NodeList, each time an element is removed, the list must be re-generated by the browser (regardless of which of the above methods is used) so this method will likely be slow where the nodeList is large.
You can avoid that by converting the list to an array first (simply iterate over it) in which case you can use either an incrementing or decrementing counter and not worry about missing members in the list (since it isn't modified when elements are removed from the document).

Related

JavaScript - Arrays - Deleting elements from an array

I've looked up arrays and how they work, looked at a lot of other stackoverflow questions on this same topic but the answer still doesn't remain clear. How can I remove a specified element from an array?
I've tried:
array.splice(5);
array.splice(i, 5);
delete array[5]; //doesn't actually delete - I know
1 of 2 things happen every time. 1. The whole array is deleted with either of the first 2 methods mentioned above. or 2. Everything before/after the element specified is removed.
For example, I had an array that contained a Clash Royale deck:
var deck = ["Barbarians", "Goblin_Barrel", "Inferno_Tower", "Fireball", "Zap", "Hog_Rider", "Spear_Goblins", "Minion_Horde"];
Then if I wanted to remove, lets say, Fireball, then I did:
deck.splice("Fireball");
And the array now looked like this:
deck = [];
So, to restate my question. How do I remove a specified, and only the specified, element from an array?
Check the usage for splice in a JavaScript reference. You need to pass in the index of the thing to delete, then how many things to delete.
First find the index of element then remove it using splice.
Find Index of element
var index = deck.indexOf("Fireball");
Now remove element using splice.
if (index > -1) {
deck.splice(index,1);
}
if duplicate values exists then
for(ind = 0 ; ind <deck.length; ind++){
if(deck[ind]=="Fireball"){
deck.splice(ind--,1);
}
}

Get the last item from node list without using .length

The following command
document.querySelectorAll('#divConfirm table')[1].querySelectorAll('tr')
gives a node list with 3 tablerow (tr) elements in it. If I know the list size, I can access the last element via.item(2).
Is there a way to get the last element directly without resorting to .length first?
There's at least one way
var els = document.querySelectorAll('#divConfirm table')[1].querySelectorAll('tr');
var last = [].slice.call(els).pop();
but, the following statement
But if I do not know the length prior to running the script
makes no sense, you already have the collection of elements, so you would always know the length
var els = document.querySelectorAll('#divConfirm table')[1].querySelectorAll('tr');
var last = els[els.length - 1];
Another option as the8472's answer suggests would be
document.querySelector('#divConfirm table:nth-child(2) tr:last-child');
Since NodeList doesn't have a pop method.
Using the spread syntax in a new array, then pop() to get the last element.
This basically copy the Nodelist as a regular array, thus the pop() and other array methods become available.
console.log(
// Last elem with pop()
[...document.querySelectorAll("div")].pop()
)
console.log(
// 2nd elem
[...document.querySelectorAll("div")].slice(1)[0]
)
console.log(
// By index :) just in case
document.querySelectorAll("div")[0]
)
<div>The sun</div>
<div>is</div>
<div>shinning</div>
depending on circumstances this may work: document.querySelector('#divConfirm table tr:last-of-type')
You can transform the NodeList into an Array. Then can use array.pop(). It return the last item BUT remove it to the array!
const elementsArray = Array.from(elements);
elementsArray.pop()

Fast find for indices by ID

I have million of objects each have an unique ID - number.
Each object for making it simple contains name
They objects are being added into array.
Into this array i'm adding and removing objects.
In order to remove object I have the id, and then need to find the index in the array and splice it out.
In my case i have allot of objects and can have allot of removes operations. so in case i have 1000 removes. and all of this objects ids are stored in the end of the array, than i will run over the all 1 million objects till i find them.
Storing the index in the object after adding is not good, because every each remove i need to update the indices of all objects stored after the removed one.
For example removing the first 1000 will cause updating the rest of the 1M-1000 items indices.
My question is, what is the best solution for my problem?
-- UPDATE --
for example: My flat array look like this after adding 1M objects
[ obj1, obj2, obj3, .... obj1000000 ]
I want to remove now the object obj1000000. For finding which index this object
was inserted to i need to run over all the array (or till i found the item) and compare the current item id with my obj1000000 id, and break out from the loop when found. Then remove the item by it's index.
If i would store the index of each object in the object itself after it being added to the array, i would have to update the rest of the objects indices after removing one.
For example: obj1 will contains property index=0, obj2 will have index=1 and so on. To remove obj5 i just get its property index which is 4 and remove it. but now obj6 which has index=5 is incorrect. and should be 4. and obj7 should be 5 and so on. so update must be done.
My SmartArray holds an TypedArray created in some size. And i'm expending it if needed. When push is called. I'm simply set the value in the last item this._array[this.length++] = value; (Checking of course if to expand the array)
SmartArray.prototype.getArray = function () {
return this._array.subarray(0, this.length);
}
SmartArray.prototype.splice = function (index, removeCount) {
if (index + removeCount < this.length) {
var sub = this._array.subarray(index + removeCount, this.length);
this._array.set(sub, index);
} else {
removeCount = this.length - index;
}
this.length -= removeCount;
}
It is working very fast, subarray doesn't create a new array. And set is working very fast as well.
The standard solutions for this problem are
balanced (binary) trees,
hash tables.
They take respectively O(Log(N)) and O(1) operations per search/insertion/deletion on average.
Both can be implemented in an array. You will find numerous versions of them by web search.

removechild loop exits before finish

I have the following piece of code that finds all elements in the document with classname foo and then removes them all
function(doc) {
var items = doc.getElementsByClassName('foo');
alert(items.length);
if(items.length>0) {
for(var i=0;i<items.length;i++) {
alert(i);
doc.body.removeChild(items[i]);
}
}
Forexample, the items.length is 3 and the function exits after running one loop and when the length is 8 it exits at 3. Any help would be greatly appreciated. Also, when I run the function again and again it does eventually remove all elements.
Your problem is that the NodeList returned by getElementsByClassName() is live. Either convert it into an array first as Felix suggests or iterate backwards:
var items = doc.getElementsByClassName('foo');
var i = items.length;
while (i--) {
items[i].parentNode.removeChild(items[i]);
}
This works because the item removed from the list each iteration is the last item in the list, therefore not affecting earlier items.
I also changed doc.body to items[i].parentNode for greater generality, in case you need to deal with elements that are not direct children of the <body> element.
The problem is that items is a live NodeList, i.e. whenever you access a property of the list (items.length), the list is reevaluated (elements are searched again).
Since you delete elements in the meantime, the list becomes shorter, but you keep the index.
You could convert the NodeList to an array first:
var items = [].slice.call(doc.getElementsByClassName('foo'));
The array size won't change when you delete the DOM elements.

Problems with JavaScript "for in" loop

I have an array of objects which will be the basis for a certain menu in my website. It will be build using JavaScript:
[
{"menuName":"Contact Info","sectionName":"contacts"},
{"menuName":"Facilities","sectionName":"facilities"},
{"menuName":"Locations","sectionName":"locations"},
{"menuName":"Packages","sectionName":"packages"},
{"menuName":"Policies","sectionName":"policies"},
{"menuName":"Reviews","sectionName":"reviews"},
{"menuName":"Rooms","sectionName":"rooms"}
]
So I decided to use the "for in loop" so that I won't have to deal with indexes and lengths. I expect seven items to appear in the menu when it gets built (I'll be using <ul> and <li>).
When I was debugging and accidentally added a background color to the <li>, is when all hell broke loose. I found at least 30 empty <li> after the visible 7th menu <li>.
Why is this happening?
EDIT:
Here's the loop. The loop creates another object for another function to parse later on. (It creates an <li> with an <a> inside with properties provided by the previous array.) I know that the other function works fine because when I change this "for-in" loop to an ordinary for loop, or while loop, it works fine.
this.sectionList = function(menu, id) {
var list = new Array();
for(var i in menu) {
var listItem = {
"element" : "li",
"contains" : [{
"element" : "a",
"attr" : {
"href" : menu[i].sectionName + ':' + id
},
"contains" : menu[i].menuName
}]
}
list.push(listItem);
}
}
for in iterates over object properties. Javascript arrays are just a specific kind of object with some handy properties to help you treat them as just arrays, but they still have internal object properties .. and you don't mean to iterate over these).
So, you shouldn't use for in to iterate over arrays. This only became evident to you when you added your background colour, but it'll always be the case.
Instead, loop with a counter and array .length.
Your object gets methods and properties passed by JavaScript itself. Those are methods that every object gets when its created.
You have to use .hasOwnProperty to find only the properties and methods you assigned to the object!
for(var i in myObject){
if(myObject.hasOwnProperty(i)){
console.log(myObject.i);
}
}
Hope that helps!
Here are two articles that helped me two understand it better:
http://bonsaiden.github.com/JavaScript-Garden/#object.hasownproperty
http://javascriptweblog.wordpress.com/2011/01/04/exploring-javascript-for-in-loops/
I see no difference between the two ways of iterating your data structure in this jsFiddle: http://jsfiddle.net/jfriend00/HqLdk/.
There are lots of good reasons why you should not use for (x in array) on arrays. The main reason is that that type of iteration iterates over the properties of the object, not just the array elements. Those properties can include other properties of the array if any have been added where as the for (var i = 0; i < array.length; i++) method will never have issues with added properties because by definition, it only iterates over the array elements.
It is somewhat luck that when no additional properties have been added to the array object, that iterating over the properties happens to include just the array elements. The language does not want you to iterate array elements that way. You should iterate arrays with
for (var i = 0; i < array.length; i++).
I understand the seduction of the simpler syntax, but it is not the right way to do it.

Categories

Resources