I want to use lazy loading effect and in my code everything is going ok, but querySelector section.
I've stored some elements in a variable and I wanna apply observer function on theme.
And I also print every output in console.log to see the things.
But this error happens:
Uncaught TypeError: imgs.forEach is not a function
This is my code:
const imgs = document.querySelector("[data-src]");
const options = {
threshold:1,
};
const observer = new IntersectionObserver((entries,observer) => {
entries.forEach(entry => {
let src = entry.target.getAttribute('data-src');
if(!entry.isIntersecting){
return;
}
entry.target.src=src;
console.log(entry)
observer.unobserve(entry.target);
})
},options)
// Probleme is here
imgs.forEach(img => {
observer.observe(img);
})
Try with querySelectorAll like below code,
const imgs = document.querySelectorAll("[data-src]");
as querySelector will return single matched element, but querySelectorAll will return an NodeList of all matched elements.
Use querySelectorAll instead that should fix it
Reference the mdn documentation
The Document method querySelectorAll() returns a static (not live)
NodeList representing a list of the document's elements that match the
specified group of selectors.
instead of
const imgs = document.querySelector("[data-src]");
try this
const imgs = document.querySelectorAll("[data-src]");
Although for some browser using querySelectorAll(selector).forEach() will work. But it is not supported by all browsers. So the safe way to do this is using a for loop for looping over the NodeList. So you should do something like this,
const imgs = document.querySelector("[data-src]");
// other coddes...
for(let i = 0; i<imgs.length; i++) {
// your code.
}
I think this will be the safest way.
Document.querySelector()
returns a single element and you cannot loop over a single element.
document.querySelectorAll()
returns all the elements with the class, id, tagname etc provided in the parenthesis.
Related
I want to use lazy loading effect and in my code everything is going ok, but querySelector section.
I've stored some elements in a variable and I wanna apply observer function on theme.
And I also print every output in console.log to see the things.
But this error happens:
Uncaught TypeError: imgs.forEach is not a function
This is my code:
const imgs = document.querySelector("[data-src]");
const options = {
threshold:1,
};
const observer = new IntersectionObserver((entries,observer) => {
entries.forEach(entry => {
let src = entry.target.getAttribute('data-src');
if(!entry.isIntersecting){
return;
}
entry.target.src=src;
console.log(entry)
observer.unobserve(entry.target);
})
},options)
// Probleme is here
imgs.forEach(img => {
observer.observe(img);
})
Try with querySelectorAll like below code,
const imgs = document.querySelectorAll("[data-src]");
as querySelector will return single matched element, but querySelectorAll will return an NodeList of all matched elements.
Use querySelectorAll instead that should fix it
Reference the mdn documentation
The Document method querySelectorAll() returns a static (not live)
NodeList representing a list of the document's elements that match the
specified group of selectors.
instead of
const imgs = document.querySelector("[data-src]");
try this
const imgs = document.querySelectorAll("[data-src]");
Although for some browser using querySelectorAll(selector).forEach() will work. But it is not supported by all browsers. So the safe way to do this is using a for loop for looping over the NodeList. So you should do something like this,
const imgs = document.querySelector("[data-src]");
// other coddes...
for(let i = 0; i<imgs.length; i++) {
// your code.
}
I think this will be the safest way.
Document.querySelector()
returns a single element and you cannot loop over a single element.
document.querySelectorAll()
returns all the elements with the class, id, tagname etc provided in the parenthesis.
I have two the same forms on the same page and script that works only for the first form.
I'm a beginner and this is a challenge for me; I tried add the `for (var i = 0; i < input.length; i++) but it doesn't work out. I will be grateful for any help.
var el = document.querySelector(".js-tac");
input = document.querySelector('.js-tel')
input.addEventListener('input', evt => {
const value = input.value
if (!value) {
el.classList.remove("is-visible");
return
}
const trimmed = value.trim()
if (trimmed) {
el.classList.add("is-visible");
} else {
el.classList.remove("is-visible");
}
})
document.querySelector return the first matched element. So you need document.querySelectorAll which will give a collection. Then iterate that collection like this
document.querySelectorAll('.js-tel').forEach((input)=>{
// not using arrow function since using this to target the element
input.addEventListener('input', function(evt){
const value = this.value
// rest of the code
})
})
The problem is that you are only getting one input element. (querySelector returns the first matching element, not all matching elements). You likely want to use querySelectorAll to get a NodeList (which will contain all matching nodes). You can iterate over those.
Based on how you seem to be using it, I'd recommend making sure your js-tac and js-tel are wrapped in some common parent, and use querySelectorAll to find those. Then, you can use querySelector to find the js-tel and js-tac.
var nodes = document.querySelectorAll('.js-parent')
//If you don't export forEach to be available, you can also just do a standard
//for loop here instead.
nodes.forEach((parent) => {
var el = parent.querySelector(".js-tac");
input = parent.querySelector('.js-tel')
...
})
I have <ul class="container" id="container"></ul> where I conditionally add li elements. I create selector with - cards: Array.from(document.getElementsByTagName('li')). So when a program starts selector is empty, because there are no li elements. The problem then is using the cards selector in other parts of my code. If I import it from my selectors file it just won't work. But if I create same selector in a function that needs cards, it works. As I understand getElementsByTagName should make updates automatically.
The getElementsByTagName method of Document interface returns an HTMLCollection of elements with the given tag name. The complete document is searched, including the root node. The returned HTMLCollection is live, meaning that it updates itself automatically to stay in sync with the DOM tree without having to call document.getElementsByTagName() again.
Question why imported selector won't work when the same selector declared in function that uses it works? It seems to me that I'm missing something.
Code example: base.js
export const elements = {
cards: Array.from(document.getElementsByTagName('li')),
...
}
deckview.js
import { elements } from './base'
export const toggleClassOnClick = () => {
// this works
let cards = Array.from(document.getElementsByTagName('li'))
// this won't work
// let cards = elements.cards
cards.forEach(card => {
card.addEventListener('click', function() {
card.classList.value === 'card'
? card.classList.add('is-flipped')
: card.classList.remove('is-flipped')
// disabling ability to press on the opened card
if (card.classList.value === 'card is-flipped') {
card.style.pointerEvents = 'none'
}
})
})
}
document.getElementsByTagName('li') will return a live collection, but Array.from will take the data from it and make an regular array. The array is just an array, it isn't live.
const lis = document.getElementsByTagName('li');
const array = Array.from(lis);
console.log("Before: ", lis.length, array.length);
const li = document.createElement("li");
li.textContent = "Goodbye";
document.querySelector("ul").appendChild(li);
console.log("After: ", lis.length, array.length);
<ul><li>Hello</li></ul>
I'm trying to make a chrome extension. A part of the code (early on in the making of this extension) involves fetching several elements by their class name. There are several elements whos class name all look like this: "scollerItem [AlotOfRandomCharacters]".
So I'm trying to list all classNames that start with "scrollerItem", but i'm not quite sure how to go about it.
So here's my code so far:
function initRE(){
var matchingItems = [];
var allElements = document.getElementsByTagName("div");
for(i=0; i < allElements.length; i++)
{
if ( allElements [i].className == "scrollerItem" && "*" )
{
matchingItems.push(allElements[i]);
}
}
alert(matchingItems[0]);
}
allElements is listed in the breakpoint watchlist as "HTMLCollection(623)" (roughly), but nothing is forwarded to the "matchingItems" array.
I've tried [i].className.contains and .includes
Direct copy of one of the HTML Elements in question:
<div class="scrollerItem s1d8yj03-2 ebdCEL Post t3_agnhuk s1ukwo15-0 RqhAo" id="t3_agnhuk" tabindex="-1">
You can try to use Document.querySelectorAll() with a CSS selector matching all classes starting with your target string.
let elems = document.querySelectorAll("div[class^='scrollerItem'], div[class*=' scrollerItem]");
let classes = Array.from(elems).map(e => Array.from(e.classList)).reduce((arr, res) => {
res = res.concat(arr);
return res;
}, []).filter(cls => cls.startsWith('scrollerItem'))
Additional explanation of CSS selector syntax: Is there a CSS selector by class prefix?
Since the class scrollerItem exists on the element, you can use document.querySelectorAll() with the .scrollerItem as the query:
const result = document.querySelectorAll('.scrollerItem');
console.log(Array.from(result));
<div class="scrollerItem s1d8yj03-2 ebdCEL Post t3_agnhuk s1ukwo15-0 RqhAo" id="t3_agnhuk" tabindex="-1">
Use classList not className:
if (allElements[i].classList.contains("scrollerItem") {...}
How get an array of the values of elements which have same class?
When I do this I get only the first element, but I want a whole array:
var classes = document.querySelector(".klass").value;
alert(classes); //Outputs only the first element
And I want to get a full array of the values of the inputs:
<input type="text" class="klass" />
<input type="text" class="klass" />
<input type="text" class="klass" />
Is that possible?
Use document.querySelectorAll to retrieve a NodeList (see also the section "How can I convert NodeList to Array?") then cast it to an array and map a function that returns each element's value.
var classesNodeList = document.querySelectorAll(".klass");
var classes = Array.prototype.slice.call(classesNodeList).map(function(element) {
return element.value;
});
Update
As stated in the comment by Ginden, a shorter way to do this is to pass the NodeList to Array.prototype.map using Function.prototype.call
var classesNodeList = document.querySelectorAll(".klass");
var classes = Array.prototype.map.call(classesNodeList, function(element) {
return element.value;
});
For such a simple CSS selector expression, I would use getElementsByClassName and give it the class name, rather than querySelectorAll. getElementsByClassName is generally faster than using querySelectorAll by several orders of magnitude. See this jsperf.
var classes = document.getElementsByClassName("klass"); // Do not use a period here!
var values = Array.prototype.map.call(classes, function(el) {
return el.value;
});
getElementsByClassName is usually faster than querySelectorAll. Browsers index elements by class name already to optimize the speed of CSS transformations. getElementsByClassName returns an HTMLCollection element, so it does not have the Array methods and you need to use Array.prototype... on this too.
You need to loop through your array of elements and get the value of each one.
var classes = document.querySelectorAll(".klass").value,
values = [];
for(var i = 0; i < classes.length; i++) {
values.push(classes[i].value);
}
Note that this may not be as clean as using [].map, but is a good deal faster.
You can use querySelectorAll method first and then use array's map function to retrieve the result:
var elements = document.querySelectorAll('.klass');
var values = [].map.call(elements, function(e) {
return e.value;
});