Can i use query selector to find dynamically created elements that have an attribute?
I want to find the first element with val, but this won't find them. (divs with the values a-d are there just to show this works with "normally" created elements.)
let i = 4, wrapper = document.getElementsByClassName("wrapper")[0];
while (i-- > 0) {
let div = document.createElement("div");
div.val = i;
wrapper.appendChild(div);
}
let myDiv = document.querySelector(".wrapper div[val]");
console.log("myDiv", myDiv);
<div class="wrapper">
</div>
<div class="wrapper">
<div val="a"></div>
<div val="b"></div>
<div val="c"></div>
<div val="d"></div>
</div>
Use Element.setAttribute() to set the attributes so they can be found by the querySelector:
let wrapper = document.getElementsByClassName('wrapper')[0]
let i = 4
while (i--) {
let div = document.createElement('div')
div.setAttribute('val', i)
wrapper.appendChild(div)
}
let myDiv = document.querySelector('.wrapper div[val]')
console.log('myDiv', myDiv)
<div class="wrapper"></div>
Related
How do I make a button using javascript that makes a new div element with a new id each time the button is pressed.
This is what I want the html to look like. But I want it to be made with javascript.
<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
I am a new self taught coder so be gentle please.
Thanks.
You can create a element using document.createElement() method, then set it's id by id property and then append it to the DOM, in this case I appended the element to the body.
var element = document.createElement("DIV");
element.id = "4";
document.body.appendChild(element)
Here is an example of generating an element on button click with new id each time:
var base = 0;
function addElement() {
base++
var element = document.createElement("DIV");
element.id = base;
element.innerHTML = base
document.body.appendChild(element)
}
<button onclick="addElement()">Add element!</button>
var base = 0;
function addElement() {
base++
var element = document.createElement("DIV");
element.id = base;
element.innerHTML = base
document.body.appendChild(element)
}
You can do it using a static id variable to keep track of the generated incremented number.
For the div generation, you can use the document.createElement method which creates the HTML element specified by tagName (div in your case)
let id = 0;
function createDiv(){
var element = document.createElement("DIV");
element.id = id;
element.textContent = id;
id++;
document.body.appendChild(element)
}
<button onclick="createDiv()">Add div</button>
I have this simple html code. I need to be able to determine if the ::before is being applied to .icon-player-flash
<div id="TestSwitch">
<i class="icon-player-html5"></i>
<i class="icon-player-none"></i>
<i class="icon-player-flash"></i>
</div>
I thought this would work but it's always returning 0 for the length.
var flashplayer = $(".icon-player-flash:before");
console.log("count: " + flashplayer.length);
What am I missing?
Use getComputedStyle and check the value of content. If it's none then the pseudo element isn't defined:
var elem = document.querySelector(".box");
var c = window.getComputedStyle(elem,"before").getPropertyValue("content");
console.log(c);
var elem = document.querySelector(".alt");
var c = window.getComputedStyle(elem,"before").getPropertyValue("content");
console.log(c);
.box:before {
content:"I am defined"
}
<div class="box"></div>
<div class="alt"></div>
This property is used with the :before and :after pseudo-elements to generate content in a document. Values have the following meanings:
none
The pseudo-element is not generated. ref
If you want to count simply consider a filter:
const elems = document.querySelectorAll('div');
const divs = [...elems].filter(e => {
var c = window.getComputedStyle(e,"before").getPropertyValue("content");
return c != "none"
});
console.log(divs.length)
.box:before {
content:"I am defined"
}
<div class="box"></div>
<div class="box alt"></div>
<div class="alt"></div>
<div ></div>
For example, in jQuery, if i want all <div> and <p> elements, I do this:
var $x = $("p, div");
And then if i want all the <div> elements in x, then I do this:
var $divs = $x.filter("div");
So how do i do this simple filter thing in vanilla JavaScript?
For example, to select all <div> and <p>, then I can do this:
var x = document.querySelectorAll("div, p");
But vanilla JavaScript doesn't have the filter function like in jQuery, so I can't do this:
var divs = x.filter("div"); // ERROR
Hope someone can help me with this :-)
Thanks in advance.
UPDATE
Some comments/answers have suggested to do something like .tagName == "DIV" to find the divs, however, i want a solution with a string selector like in jQuery.
The reason is because i also want to filter with attributes, classes and even multiple selectors where you put in comma. And the string selector must be dynamic.
That means, i dont know whats in the selector. It could be "div[foo='asd'], .bar" or "#hello, [xx='yy'], p"
So i cant just hardcode the .tagName == "DIV", beacuse i dont know whats in the selector string.
You can use the matches function to check if a CSS selector matches a given element.
var x = document.querySelectorAll("div, p");
var divs = [];
// Iterate through the elements that the first query selector matched
// (is a paragraph or a div tag)
for (var elem of x) {
// Check if the given element matches the second query selector
// (is a div tag)
if (elem.matches('div')) {
divs.push(elem);
}
}
This code can be written more succinctly (and with more modern code) using:
let x = document.querySelectorAll("div, p");
let divs = Array.from(x).filter(elem => elem.matches("div"));
you can combine Array.filter() with Element.matches()
var x = document.querySelectorAll("div, p");
var divs = x.filter(y => y.matches("div"));
// for p tags
var paragraphs = x.filter(y => y.matches("p"));
//for both div and p tags
var mix = x.filter(y => y.matches("div, p"));
you can use Array.filter
const elems = document.querySelectorAll('p, div');
const divs = [...elems].filter(e => {
return e.tagName == 'DIV'
});
console.log(divs)
<div id="div1"></div>
<div id="div2"></div>
<div id="div3"></div>
<p id="p1"></p>
<p id="p2"></p>
<p id="p3"></p>
you can change e.tagName to filter with something else :
const elems = document.querySelectorAll('p, div');
const divs = [...elems].filter(e => {
return e.tagName == 'DIV'
});
const byId = [...elems].filter(e => {
return e.id == 'div1'
});
const byClass = [...elems].filter(e => {
return e.className == 'class1'
});
console.log(byClass)
<div id="div1" class="class1"></div>
<div id="div2" class="class1"></div>
<div id="div3" class="class2"></div>
<p id="p1" class="class1"></p>
<p id="p2" class="class2"></p>
<p id="p3" class="class2"></p>
querySelectorAll returns a NodeList not an array.
You'll need to convert it to an array
var arr = Array.prototype.slice.call(x);
var divs = arr.filter(el => { return el.tagName == 'DIV' });
A very naive approach:
function get(selector) {
const els = document.querySelectorAll(selector);
return {
selector,
length: els.length,
get: i => els[i],
[Symbol.iterator]: () => els[Symbol.iterator](),
filter: f => get(selector + ", " + f)
};
}
Usable as:
const menus = get(".menu");
for(const el of menus) console.log(el);
console.log(menus.filter("div").get(0));
I have a set of elements and want to remove its container wrapper in Javascript.
I've researched around (this, this, and this) but I need a solution that 1) doesn't involve jQuery. 2) and can work on multiple elements.
HTML:
<div class="global-container stacked">
<article class="global"></article>
<article class="global"></article>
</div>
I've tried:
var globalArticles = document.getElementsByClassName('global');
globalArticles.outerHTML = globalArticles.innerHTML;
But that doesn't work. How would one go about removing the wrapper from all article.global?
You could just create your own unwrap() method, something like this
function unwrap(elems) {
elems = 'length' in elems ? elems : [elems];
for (var i = 0; i < elems.length; i++) {
var elem = elems[i];
var parent = elem.parentNode;
var grandparent = parent.parentNode;
grandparent.insertBefore(elem, parent);
if (parent.children.length === 0)
grandparent.removeChild(parent);
}
}
var globalArticles = document.getElementsByClassName('global');
unwrap(globalArticles);
You can use .innerHTML, .removeChild(), .insertAdjacentHTML()
var container = document.querySelector(".global-container");
var html = container.innerHTML; // store `html` of `container`
container.parentElement.removeChild(container); // remove `container`
document.body.insertAdjacentHTML("beforeend", html); // append `html`
<div class="global-container stacked">
<article class="global">1</article>
<article class="global">2</article>
</div>
This should work:
var globalArticle = document.getElementsByClassName('global')[0];
if (globalArticle) {
globalArticle.parentElement.outerHTML = globalArticle.parentElement.innerHTML;
}
From my understanding, document.querySelector returns a Node object. I can then call appendChild on this object.
I execute the following code to append a bunch of divs to my container div:
var container = document.querySelector('.container');
for (var i = 0; i < 400; i++) {
var block = document.createElement('div');
block.className = 'block';
container.appendChild(block);
}
And end up with the following structure:
<div class="container">
<div class="block"></div>
<div class="block"></div>
...
<div class="block"></div>
</div>
How can I loop through each element in my container div and add a new class to it using my existing container variable?
I have tried this:
...
container.childNodes[i].className = 'myClass';
It seems I need to access the Element object of the child Node, but I'm not sure how to do this.
Can you not just add it when you create the divs ?
var container = document.querySelector('.container');
for (var i = 0; i < 400; i++) {
var block = document.createElement('div');
block.className = 'block myClass';
container.appendChild(block);
}
To add classes to the elements in the container variable, I used the following code:
container.children[i].className = 'myClass';
I had to use children instead of childNodes. You can see the context in which this code was used here: http://codepen.io/robkom/pen/RWmodz.