Unable to select all image elements - javascript

I'm using an intersection observer to implement lazy loading on my images. If I only select one image with the querySelector, then it works. But for some reason I can't get querySelectorAll to work. I also tried getElementsByClassName and this is still not working. Any solutions??
html:
<section class="section" id="section--2">
<div class="photo__container--two">
<img
data-src="portrait/4-vertical.JPG"
alt=""
class="fade-in img-vertical-lazy"
/>
<img
data-src="portrait/5-vertical.JPG"
alt=""
class="fade-in img-vertical-lazy"
/>
<img
data-src="portrait/6-vertical.JPG"
alt=""
class="fade-in img-vertical-lazy"
/>
</div>
</section>
JavaScript:
const lazyImages = document.querySelectorAll('.img-vertical-lazy');
const lazyLoading = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (!entry.isIntersecting) return;
entry.target.src = entry.target.getAttribute('data-src');
lazyLoading.unobserve(entry.target)
});
});
lazyLoading.observe(lazyImages);

According to the InstersectionObserver docs, the observe function receives a single node, not an array of nodes
You should rewrite the last line to this
lazyImages.forEach(image => lazyLoading.observe(image))

Related

Puppeteer: How get img src inside nested selector?

I have a structure like this:
<div class="loaded active">
<img class="full" src="img1.jpg">
</div>
<div class="loaded">
<img class="full" src="img2.jpg">
</div>
<div class="loaded">
<img class="full" src="img3.jpg">
</div>
I need get link of img1.jpg.
I can get links for class="full":
const slkImg = '.full';
const imgs = await page.$$eval(slkImg, postLinks => postLinks.map(link => link.src));
but I don't know how do it for only img1.jpg.
As discussed in the comments,
page.$eval('.loaded.active .full', el => el.src)
works thanks to two things:
Using $eval rather than $$eval to select one element
Using .loaded.active .full to select the first .full descendent of the first .loading.active parent.

Remove last <img> inside a <div> [duplicate]

This question already has answers here:
How to remove last element from div?
(4 answers)
Closed 1 year ago.
I have <div> containing multiple <img>.
<div class="content">
<img src="img.png"/>
<img src="img.png"/>
<img src="img.png"/>
<img src="img.png"/>
</div>
The quantity <img> inside the <div> is dynamic.
I have a function that can remove all <img>. How do I modify the function to only remove last <img> inside the <div>?
document
.querySelectorAll(".content img")
.forEach((img) => img.remove());
querySelectorAll creates an array. So you just need to remove the last thing which is in the array. Something like this should work
const images = document.querySelectorAll(".content img")
images[images.length - 1].remove()
There are a number of ways to do what you are asking. Keep in mind that the return value of querySelectorAll is an array-like NodeList which can be accessed using standard array syntax, implements some array methods (forEach for example) or can be coerced to an array.
If you want to keep working with the result of querying all img elements in your div you can simply access the last element in the returned NodeList and remove it.
const images = document.querySelectorAll('.content img');
images[images.length-1].remove();
// or spread the NodeList to an array and pop
[...document.querySelectorAll('.content img')].pop().remove();
Alternatively, you can query the last img element directly using either :last-child or :last-of-type
document.querySelector('.content img:last-child').remove();
// or
document.querySelector('.content img:last-of-type').remove();
document
.getElementById('lastchild')
.addEventListener('click', () => document.querySelector('.content img:last-child').remove());
document
.getElementById('lasttype')
.addEventListener('click', () => document.querySelector('.content1 img:last-of-type').remove());
document
.getElementById('lastindex')
.addEventListener('click', () => {
imgs = document.querySelectorAll('.content2 img');
imgs[imgs.length - 1].remove()
});
document
.getElementById('pop')
.addEventListener('click', () => [...document.querySelectorAll('.content3 img')].pop().remove());
<div class="content">
<img src="https://source.unsplash.com/random/100x100/?sig=1"/>
<img src="https://source.unsplash.com/random/100x100/?sig=2"/>
<img src="https://source.unsplash.com/random/100x100/?sig=3"/>
<img src="https://source.unsplash.com/random/100x100/?sig=4"/>
</div>
<button type='button' id='lastchild'>Remove :last-child</button>
<hr>
<div class="content1">
<img src="https://source.unsplash.com/random/100x100/?sig=5"/>
<img src="https://source.unsplash.com/random/100x100/?sig=6"/>
<img src="https://source.unsplash.com/random/100x100/?sig=7"/>
<img src="https://source.unsplash.com/random/100x100/?sig=8"/>
</div>
<button type='button' id='lasttype'>Remove :last-of-type</button>
<hr>
<div class="content2">
<img src="https://source.unsplash.com/random/100x100/?sig=9"/>
<img src="https://source.unsplash.com/random/100x100/?sig=10"/>
<img src="https://source.unsplash.com/random/100x100/?sig=11"/>
<img src="https://source.unsplash.com/random/100x100/?sig=12"/>
</div>
<button type='button' id='lastindex'>Remove imgs[length-1]</button>
<hr>
<div class="content3">
<img src="https://source.unsplash.com/random/100x100/?sig=13"/>
<img src="https://source.unsplash.com/random/100x100/?sig=14"/>
<img src="https://source.unsplash.com/random/100x100/?sig=15"/>
<img src="https://source.unsplash.com/random/100x100/?sig=16"/>
</div>
<button type='button' id='pop'>Remove pop()</button>
If you want to use jQuery you can find last child and remove it.
Like this: $('.content').children('img').last().remove()
function deleteLastImg() {
$('.content').children('img').last().remove()
}
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
<button onClick="deleteLastImg()" >Delet last image</button>
<div class="content">
<img src="img.png" />
<img src="img.png" />
<img src="img.png" />
<img src="img.png" />
<span>this is span</span>
</div>
Use .lastChild.remove();
let yourDiv = document.getElementById("yourDiv");
function yourFunction () {
yourDiv.lastChild.remove();
}
<button onclick="yourFunction()">Click me</button>
<div class="content" id="yourDiv">
<img src="https://images.ctfassets.net/hrltx12pl8hq/7yQR5uJhwEkRfjwMFJ7bUK/dc52a0913e8ff8b5c276177890eb0129/offset_comp_772626-opt.jpg?fit=fill&w=800&h=300"/>
<img src="https://images.ctfassets.net/hrltx12pl8hq/7yQR5uJhwEkRfjwMFJ7bUK/dc52a0913e8ff8b5c276177890eb0129/offset_comp_772626-opt.jpg?fit=fill&w=800&h=300"/>
<img src="https://images.ctfassets.net/hrltx12pl8hq/7yQR5uJhwEkRfjwMFJ7bUK/dc52a0913e8ff8b5c276177890eb0129/offset_comp_772626-opt.jpg?fit=fill&w=800&h=300"/>
<img src="https://images.ctfassets.net/hrltx12pl8hq/7yQR5uJhwEkRfjwMFJ7bUK/dc52a0913e8ff8b5c276177890eb0129/offset_comp_772626-opt.jpg?fit=fill&w=800&h=300"/>
</div>

JS Dom manipulation issue

So i am creating a carousel generator framework and I want to make the implementation as simple as possible for the user. The developer is supposed to add
images without caring about design/responsiveness. The framework must take every image and insert it in a div with the classname of "slide". In this case from this code:
<div id="album" class="album">
<img src="./assets/img1.jpeg" alt="img1">
<img src="./assets/img2.jpeg" alt="img2">
<img src="./assets/img3.jpeg" alt="img3">
<img src="./assets/img4.jpeg" alt="img4">
<img src="./assets/img5.jpeg" alt="img5">
<img src="./assets/img6.jpeg" alt="img6">
</div>
the framework should generate this:
<div class="slide">
<img src="./assets/img1.jpeg" alt="img1">
</div>
<div class="slide">
<img src="./assets/img2.jpeg" alt="img2">
</div>
<div class="slide">
<img src="./assets/img3.jpeg" alt="img3">
</div>
<div class="slide">
<img src="./assets/img4.jpeg" alt="img4">
</div>
<div class="slide">
<img src="./assets/img5.jpeg" alt="img5">
</div>
<div class="slide">
<img src="./assets/img6.jpeg" alt="img6">
</div>
But the following code generates only 3 of the 6 images:
let album = document.getElementById("album");
let nextButton = document.getElementById('nextButton');
nextButton.addEventListener('', () => {
album.scrollBy(window.innerWidth, 0);
})
Object.keys(album.children).forEach(key => {
if (album.children[key].tagName === 'IMG') {
let newDiv = document.createElement('div');
newDiv.className = "slide";
newDiv.append(album.children[key]);
album.replaceChild(newDiv, album.children[key]);
}
})
and has an error:
Uncaught TypeError: Cannot read property 'tagName' of undefined
at Object.keys.forEach.key (index.js:9)
at Array.forEach (<anonymous>)
at index.js:8
and the generated carousel is:
Ideas? Thanks in advance.
This happens because .children creates a live collection of nodes so the iteration changes while you insert new children div inside the forEach
you could instead create a static collection like
let nodes = document.querySelectorAll('#album > img');
and iterate over that collection of nodes
let album = document.getElementById('album');
let nodes = document.querySelectorAll('#album > img');
Object.keys(nodes).forEach(i => {
let slide = document.createElement('div');
slide.className = 'slide';
slide.appendChild(nodes[i]);
album.appendChild(slide)
});
Codepen demo
The generated source is

How to add Event Listener on Multiple tag at once

I'm new in Javascript. I have this images that I want to replace on the main-img. The code below is working fine but I just want to know how to do this by using less code in Javascript.
<div id="container">
<div id="side-img">
<img id="side1" onclick="side1()" src="img1.jpeg">
<img id="side2" onclick="side2()" src="img2.jpeg">
<img id="side3" onclick="side3()" src="img3.jpeg">
<img id="side4" onclick="side4()" src="img4.jpeg">
</div>
<div id="main-img">
<img id="main" src="img0.jpeg">
</div>
</div>
<script type="text/javascript">
var sideimg = document.querySelectorAll('#side-img img');
var main = document.querySelector('#main');
function side1() {
main.src = sideimg[0].src;
}
function side2() {
main.src = sideimg[1].src;
}
function side3() {
main.src = sideimg[2].src;
}
function side4() {
main.src = sideimg[3].src;
}
</script>
You could simplify it by modifying the image tags like this:
<img id="side1" onclick="side(0)" src="img1.jpeg">
<img id="side2" onclick="side(1)" src="img2.jpeg">
<img id="side3" onclick="side(2)" src="img3.jpeg">
<img id="side4" onclick="side(3)" src="img4.jpeg">
And remove all side() functions in your JS script and add this function:
var sideimg = document.querySelectorAll('#side-img img');
var main = document.querySelector('#main');
function side(index) {
main.src = sideimg[index].src;
}
You can programatically attach an onclick handler for each image.
document.querySelectorAll('img').forEach((img) => {
img.onclick = () => {
console.log(img.src)
document.querySelector('#main').src = img.src
}
})
<div id="container">
<div id="side-img">
<img id="side1" src="img1.jpeg">
<img id="side2" src="img2.jpeg">
<img id="side3" src="img3.jpeg">
<img id="side4" src="img4.jpeg">
</div>
<div id="main-img">
<img id="main" src="img0.jpeg">
</div>
</div>
Delegation included version
JS
const viewer = document.querySelector('#main');
document.addEventListener('click', (event) => {
if (typeof event.target.hasAttribute('data-clickable') && event.target.src) {
viewer.src = event.target.src;
}
})
HTML
<div id="container">
<div id="side-img">
<img id="side1" data-clickable src="img1.jpeg">
<img id="side2" data-clickable src="img2.jpeg">
<img id="side3" data-clickable src="img3.jpeg">
<img id="side4" data-clickable src="img4.jpeg">
</div>
<div id="main-img">
<img id="main" src="img0.jpeg">
</div>
</div>
I'd suggest:
// retrieving the common ancestor element of the <img> elements:
let sideImage = document.querySelector('#side-img'),
// defining a named function, using arrow syntax; 'e' is a reference
// to the event object, passed automatically from the
// EventTarget.addEventListener() method:
imageChange = (e) => {
// we retrieve the element with the 'id' of 'main', and update
// its src property to be that of the clicked element;
// e.target retrieves the element upon which the event was
// originally triggered:
document.getElementById('main').src = e.target.src;
};
sideImage.addEventListener('click', imageChange);
let sideImage = document.querySelector('#side-img'),
imageChange = (e) => {
document.getElementById('main').src = e.target.src;
};
sideImage.addEventListener('click', imageChange);
<div id="container">
<div id="side-img">
<img id="side1" src="https://via.placeholder.com/100.png?text=image1">
<img id="side2" src="https://via.placeholder.com/100.png?text=image2">
<img id="side3" src="https://via.placeholder.com/100.png?text=image3">
<img id="side4" src="https://via.placeholder.com/100.png?text=image4">
</div>
<div id="main-img">
<img id="main" src="img0.jpeg">
</div>
</div>
JS Fiddle demo.
With reference to the question left in the comments, by the OP:
Can you please explain to me how the container #side-img was looping through each image and adding an event listener to them?
Sure, in this case we used event-delegation taking advantage of the way that events bubble through the DOM.
Rather than binding an event-listener to multiple <img> elements we took advantage of the way that events bubble through the DOM; this means that we listened for the click event as it reaches the #side-img, and look at the Event Object's target property to find the element upon which the event was initially triggered.
References:
Arrow functions.
document.getElementById().
document.querySelector().
Event delegation.
EventTarget.addEventListener().

Simple .is() not working as expected

I'm trying to loop through images, and if the last image has a class of .active, I start again. However, it is not working at all:
http://jsfiddle.net/tmyie/VE75U/
img.click(function () {
$(this).removeClass('active').next('img').addClass('active');
if ($('.active').is(':last-child')) {
img.first().addClass('active');
}
});
To check if the last image has the class .active you have to almost reverse it and first get the last image and then check for the class, and since the last-child isn't an image, that wont work
if ( $('.module.m-slide img:last').hasClass('.active') ) { ...
You have 2 issues in your code:
When you click on last image this code:
$(this).removeClass('active').next('img').addClass('active');
Will not add active class to anything, because .next('img') will return an empty array. So next line will not work too:
if ($('.active').is(':last-child'))
Because there is no active elements.
I believe you need to fix it in the following way:
if ($(this).is(':last-child'))
Next thing: none of your images can be a :last-child, because even your last image is not a last child! Look carefully at your html code:
<div class="module m-slide">
<img src="http://placehold.it/1200x800&text=1" alt="" />
<img src="http://placehold.it/1200x800&text=2" alt="" />
<img src="http://placehold.it/1200x800&text=3" alt="" />
<div class="m-slide-ctrl"></div>
</div>
Your last child is <div class="m-slide-ctrl"></div>
I suggest to change it in the follosing way:
<div class="module m-slide">
<div class="m-slide-ctrl"></div>
<img src="http://placehold.it/1200x800&text=1" alt="" />
<img src="http://placehold.it/1200x800&text=2" alt="" />
<img src="http://placehold.it/1200x800&text=3" alt="" />
</div>
Demo

Categories