replacing for loop with forEach method - javascript

I use forEach almost every time that I'm facing a node list or an actual array, but there are times, in which I can't do so, like when I want to create 5 div elements, I'm bound to do this with for loop
for (let i = 0; i < 4; i++) {
//my code to do some repetitive code ...
const myDiv = document.createElement('div');
myDiv.classList.add(`${myDiv}${i}`)
document.appendChild(myDiv);
}
The question is how can I do the same work with forEach, when there is no actual array or node list that can be used forEach method.
since forEach does the work asynchronously unlike for loop, I think it would be more beneficial move, am I wrong, any idea?

Array(3).fill().forEach((e,i) => {
const myDiv = document.createElement('div');
myDiv.classList.add(`${myDiv}${i}`)
document.appendChild(myDiv);
})

There is no problem in using the for loop, and that is exactly the right place to use a for loop (or a while).

Related

Removing and appending on wrapper in the same loop causes issues

I'm making a simple filtering function where I pass a sorted array into a function which is supposed to clear the wrapper and add the new ordered elements. My natural thought here is to do the removing and adding in the same loop, but I just can't get it to work and I can't really figure out why it wouldn't work.
Function that takes an array as argument. The sorted array is passed inside the function without any issues. The array is an Array.from(nodeList).
function removeAndAdd(sortedArray) {
for (let i = 0; i < allPosts.length; i++) {
const forumPost = allPosts[i]
forumPost.replaceWith(sortedArray[i])
}
}
NOTE: I've also tried (And alot of other stuff)
for (let i = 0; i < allPosts.length; i++) {
const forumPost = allPosts[i]
forumPost.remove()
wrapper.append(orderedArray[i])
}
My expectation is that with a single loop you should be able to clear the elements and at the same time att a new element. I don't want to use two different loops here.
Edit: I solved it by using remove() in an async function outside. I'd still love to learn technically why this didn't work.

Iterating through a jQuery array

I'm trying to iterate through an array and assign values to an element as such:
<tool>hammer</tool>
var tools = ["screwdriver", "wrench", "saw"];
var i;
for (i=0; i < tools.length; ++i){
$("tool").delay(300).fadeOut().delay(100).html(tools[i]).fadeIn();
};
However this doesn't seem to work as only "saw" is assigned as the html value and keeps fading in and out.
What am I doing wrong here?
jQuery.delay() pauses between effects queued items, so your .html() is being set instantaneously. Hence, you only see saw.
A solution is to scrap the for loop and "loop" against the length of the array, setting the tool text to the next first item in the array (as you remove it). However, you need to do this inside the context of the queue, so you can use the .fadeOut() callback to do this.
Wrap all this in a function (here, I immediately invoke it but give it a label, a, so it can be referenced, it's not anonymous) and pass that to .fadeIn() at the end so it continues the loop until the array is empty.
var tools = ["screwdriver", "wrench", "saw"];
(function a(){
if (tools.length) {
$("tool").delay(300).fadeOut(0, function(){
$(this).html(tools.shift());
}).delay(100).fadeIn(a);
}
})();
http://jsfiddle.net/tc1q1vv7/1/

Javascript remove not removing all elements

Please refer fiddle - http://jsfiddle.net/fkwwyvz8/
x = document.getElementsByClassName("buddy_blocks");
for(i=0;i<x.length;i++)
x[i].remove();
Click on the last button, and it had to remove all the other buttons, but it does not and only removes some of them, not sure why? And any way to remove all those buttons?
Since you appear to have jQuery in your code already, you can just use this to remove all buttons:
$(".buddy_blocks").remove();
Your attempt was not working for two reasons:
document.getElementsByClassName() returns a dynamic nodeList that changes underneath you each time you remove an element which causes you to miss elements in your iteration
Because a DOM element does not have a .remove() method (in most browsers anyway - it is a proposed method, but isn't widely available yet). The parent has a .removeChild() method you can use instead.
In plain Javascript, you could set up your iteration backwards so that when you remove elements and when this causes the dynamic HTMLCollection to change, it will not mess up your iteration because the changes will be the elements that you have already passed by. And, switch to use .removeChild() like this:
function f() {
var x = document.getElementsByClassName("buddy_blocks");
for(var i = x.length - 1; i >= 0; i--) {
x[i].parentNode.removeChild(x[i]);
}
}
Also, please use var on all variables that are intended to be local to your function so you are not creating "accidental global variables" which will cause hard to figure out bugs at some time in the future.
Or, in modern browsers as of 2021, you can use document.querySelectorAll() (because it doesn't return a live collection and is iterable) and you can use .remove() since all modern browsers support it:
function f() {
const items = document.querySelectorAll(".buddy_blocks");
for (let item of items) {
item.remove();
}
}
When iterating over an array and modifying it, start at the last index to avoid side effects to the current index position when you remove items
$("#c").click(function() {
f();
});
function f() {
x = document.getElementsByClassName("buddy_blocks");
for(i=x.length-1;i>=0;i--)
x[i].remove();
}
You were looping forward through the elements.
x = document.getElementsByClassName("buddy_blocks");
for(i=0;i<x.length;i++)
x[i].remove();
x is a NodeList not an array. It is a live view onto the current elements that matches the elements with that class. So when you delete the first item, what was the first item is no longer in the list, and the second item is now the first item. But, you've moved on to what was the third item, but is the new second item.
The end result is you're only removing half of the elements.
Consider either this:
//remove the first item from the NodeList until there is nothing left
x = document.getElementsByClassName("buddy_blocks");
while(x.length > 0) {
x[0].remove();
}
or:
//remove from the end of the list, which won't cause other elements to change position
x = document.getElementsByClassName("buddy_blocks");
for(i=x.length-1;i>=0;i--) {
x[i].remove();
}
I ran into the same problem and have spent a couple of hours struggling with it. With the help of other answers on this page, I have come up with :
x = document.getElementsByClassName("buddy_blocks");
while(x.length){
x[0].parentElement.removeChild(x[0]);
}
jQuery way to remove all elements with class 'buddy_blocks':
$(".buddy_blocks").remove();
fiddle
plain javascript way:
var elems = document.getElementsByClassName('buddy_blocks'),
elem;
while(elems.length){
elem = elems.item(0);
elem.parentNode.removeChild(elem);
}
fiddle
Reason for such a behavior is the variable containing the DOM element "x" is pointing to the live DOM element. So every time you remove one element, the "x" is holding the new DOM structure. So we need to use the while loop below and keep removing the 1st child from the DOM.
$("#c").click(function() {
f();
});
function f() {
x = document.getElementsByClassName("buddy_blocks");
//for(i=0;i<x.length;i++)
//x[i].remove();
var i = 0;
while(x.length) {
x[0].remove();
i++;
}
}

jquery name selector not working in ie6

var brands = document.getElementsByName("brand");
for(var brand in brands){
$("input[name='brand']").eq(brand).click(function(){
alert("hello22");
loadDataFN(1);
});
}
This code is not executing in ie6,
Any help would be appreciated.
The problem is likely that you are trying to use a for-in construct to iterate over a numeric array. This often won't give expected results. Use an incremental for loop instead:
var brands = document.getElementsByName("brand");
// Use an incremental for loop to iterate an array
for(var i=0; i<brands.length; i++){
$("input[name='brand']").eq(brands[i]).click(function(){
alert("hello22");
loadDataFN(1);
});
}
However,
after seeing the first part of your code, the loop appears unnecessary. You should only need the following, since you are assigning the same function to all brand inputs.
// These will return the same list of elements (as long as you don't have non-input elements named brand)
// though the jQuery version will return them as jQuery objects
// rather than plain DOM nodes
var brands = document.getElementsByName("brand");
$("input[name='brand']");
Therefore, the getElementsByName() and loop are not necessary.
$("input[name='brand']").click(function() {
alert("hello22");
loadDataFN(1);
});
for-in loops are used for iterating over the properties of an object, not over the elements of an array.
Why don't you write the code without jQuery if this doesn't work?
Something like this:
function getInputByName(name) {
var i, j = document.getElementsByTagName('input').length;
for(i=0;i<j;++i) { // You can also use getAttribute, but maybe it won't work in IE6
if(document.getElementsByTagName('input')[i].name === name) {
return document.getElementsByTagName('input')[i];
}
}
return null;
}
I don't know jQuery, but maybe you can do something like this:
$(getInputByName('brand')).eq(brand).click(function(){
alert("hello22");
loadDataFN(1);
});

Javascript function: nothing executes after a for(x in y) loop?

I can't seem to find the answer to this anywhere...
I have a function that needs to set the bg color of two tables. Only the first table in the function is being affected. Is only one for loop allowed in a function? ...or is the 1st for loop maybe never exiting?
I can pretty much work around this by creating multiple functions but I really want to understand why this behaves the way it does!
Thanks!
Here is my simplified code:
function setColor()
{
//This works
var t1rows=document.getElementById("table1").getElementsByTagName("tr");
var x;
for (x in t1rows)
{
t1rows[x].style.backgroundColor='yellow';
}
//this one does not work
var t2rows=document.getElementById("table2").getElementsByTagName("tr");
var y;
for (y in t2rows)
{
t2rows[y].style.backgroundColor='yellow';
}
}
getElementsByTagName() returns a NodeList object, and for-in will iterate its properties which you don't want. You want to use a straight for loop:
for(var i=0; i < t2rows.length; i++) {
t2rows[i].style.backgroundColor='yellow';
}
You're not getting to the second loop because the first is failing when it tries to access a non-existent style property on one of the NodeList's members.

Categories