I'm stuck on how to get number of all elements that has inline style.
var galleryElements = document.getElementsByClassName("popup-gallery")[0].children;
$('.myButton').click(function() {
var totalItems = galleryElements.length;
var itemsWithStyle = ($(galleryElements).css('display') == 'inline').length;
if (totalItems == itemsWithStyle){
/* do something */
}
});
Say I have a NodeList of the children of some div, i.e.
const div = document.querySelector('#target');
const children = div.children;
If I want to get the number of children with the display attribute set to inline, then I can iterate through children and increment a counter each time I encounter a child element with the display attribute set to inline.
For example:
let count = 0;
for (let child of children) {
if (child.style.display === 'inline') count++;
}
Where count represents the number of child elements of the parent div that have a display attribute set to inline.
this is without jquery
You can check this out for starters:
https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
basic
<h1 id="hello">index.html</h1>
<-- css -->
#hello {display: inline;}
// js
const title = document.getElementById('hello');
let res = window.getComputedStyle(title)
let count = 0;
if(res.getPropertyValue('display') === 'inline') {
console.log('yes')
count ++;
console.log(count)
// 1
}
what I learned:
" The object from getComputedStyle is read-only, and should be used to inspect the element's style — including those set by a element or an external stylesheet.
The element.style object should be used to set styles on that element, or inspect styles directly added to it from JavaScript manipulation or the global style attribute."
You are in fact checking if all gallery elements are display: inline, so you can simplify your code a bit:
const $galleryElements = $('.popup-gallery').first().children();
$('.myButton').click(function() {
const areAllInline = $galleryElements.filter(function () {
$(this).css('display') !== 'inline';
}).length === 0;
if (areAllInline) {
/* do something */
}
});
If there are no elements with display different than inline, you're good to go.
This will give you a tally of both inline (including inline-block) and other. If there is a class associated with the element, it will report back that as well.
$('.myButton').click(function() {
let inline = [], block = []
$('.popup-gallery *').each(function() {
let tg = $(this).prop('tagName').toLowerCase()
if ($(this).attr('class')) tg += "." + $(this).attr('class');
if (['inline','inline-block'].includes($(this).css('display'))) inline.push(tg)
else block.push(tg)
})
console.log('inline',inline)
console.log('not-inline',block)
console.log('inline/total',inline.length + "/" + (inline.length + block.length))
console.log('has inline elements?',inline.length>0)
});
.special{
display:inline;
}
.special-ib{
display:inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='popup-gallery'>
<div>A div
<ul>
<li>li list - <i>italics...</i></li>
</ul>
</div>
<div class='special'>inline div</div>
<div class='special-ib'>inline-block div</div>
<p>paragraph</p>
<span>span, <dd>dd</dd></span>
</div>
<button class='myButton'>Click me </button>
These answers are good, however I feel it is even easier than how others are solving this problem.
console.log(
[...document.querySelectorAll(".popup-gallery")]
.filter(element =>
"inline" ==
window.getComputedStyle(element)
.getPropertyValue("display")
).length
);
Related
I am trying to remove the following div from a page with my chrome extension
HTML (TO REMOVE)
<div class="base-popup js-base-popup"><div class="js-obscurity base-popup__obscurity"></div>
<div class="base-popup__indent"></div>
<div class="base-popup__wrap">
<div class="base-popup__container clearfix base-popup__container -decor" style="width:500px;">
<i class="s-icon -m -close base-popup__close js-close"></i>
<div class="base-popup__content js-content"><div><div class="s-text">Sample Text.
<!-- close tag -->
</p>
<!-- close tag in translate -->
</div></div></div>
</div>
Here is the JS in my content script
function removeElementsByClassName(names) {
var els = document.getElementsByClassName(names),
i, element;
for (i = els.count - 1; i > 0; i -= 1) {
element = els[i];
element.parentElement.removeChild(element);
}
}
removeElementsByClassName('base-popup js-base-popup');
getElementsByClassName only accepts a single class name, but you're giving it two. Since the HTML you've shown only has a single element that has either of the two classes you're using, if that's the only element you want to remove, just pick one:
removeElementsByClassName("base-popup");
// or
removeElementsByClassName("js-base-popup");
Alternately, you could use querySelectorAll with a CSS selector:
function removeElementsBySelector(selector) {
var els = document.querySelectorAll(selector),
i, element;
for (i = els.count - 1; i > 0; i -= 1) {
element = els[i];
element.parentElement.removeChild(element);
}
}
Then if you want to remove elements that have either class:
removeElementsBySelector('.base-popup, .js-base-popup');
Or if you only want to remove a single element that has both classes:
removeElementsBySelector('.base-popup.js-base-popup');
And as this is a Chrome extension, you can do that rather more simply with Array.from, forEach, and Element#remove:
function removeElementsBySelector(selector) {
Array.from(document.querySelectorAll(selector)).forEach(element => {
element.remove();
});
}
your javascript is completely wrong. the right way:
function removeElementsByClassName(names){
names=names.split(" ");//you just get elems by one class so you need to split it into multiple operations
for(var a=1;a<names.length;a++){//ability to remove multiple classes
removeElementsByClassName(names[a]);
}
var els = document.getElementsByClassName(names[0]);
for (var i =0; i<els.length ; i++) { // its length not count
var element = els[i];
element.parentElement.removeChild(element);
}
}
removeElementsByClassName('base-popup js-base-popup');
this removes all elements that contain one of these classes, if you wanted sth else see the other solution.
I have been searching the forums but unable find any specific help in relation to my problem. I am trying to design an application using javascript which will count div elements which are either hidden or visible.
I am using
document.getElementById("div-element").childElementCount;
and could use something like:
document.querySelectorAll('#div-element .dic-class').length;
both of which work as intended by returning the total elements.
I am changing the visibility of specific div elements by:
document.getElementById('div-element').style.display == "block or none";
For something like this Array.prototype.filter comes to mind (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), but you can't use that on a nodelist, which is what you get when using querySelectorAll, so I would solve this by converting the nodelist to an array, then use filter on that.
To convert a nodelist to an array:
var array = [].slice.call(someNodeList);
(https://davidwalsh.name/nodelist-array)
So, we can do this:
//gives node list
divs = document.querySelectorAll('#div-element > div');
//convert to an array
var divsArray = [].slice.call(divs);
//so now we can use filter
//find all divs with display none
var displayNone = divsArray.filter(function(el) {
return getComputedStyle(el).display === "none"
});
//and all divs that are not display none
var displayShow = divsArray.filter(function(el) {
return getComputedStyle(el).display !== "none"
});
//and use length to count
var numberOfHiddenDivs = displayNone.length;
var numberOfVisibleDivs = displayShow.length;
Just a note: its important to use getComputedStyle (https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle) rather than element.style because element.style will not reflect properties applied by css, it will only reflect inline styles.
Second note, this only counts "display:none;" as hidden, if you also want to include visibility:hidden; or some other criteria, use
var displayNone = divsArray.filter(function(el) {
return getComputedStyle(el).display === "none" ||
getComputedStyle(el).visibility === "hidden"
});
//and all divs that are not display none
var displayShow = divsArray.filter(function(el) {
return !(getComputedStyle(el).display === "none" ||
getComputedStyle(el).visibility === "hidden")
});
Demo:
//gives node list
divs = document.querySelectorAll('#div-element > div');
//convert to an array
var divsArray = [].slice.call(divs);
//so now we can use filter
//find all divs with display none
var displayNone = divsArray.filter(function(el) {
return getComputedStyle(el).display === "none"
});
//and all divs that are not display none
var displayShow = divsArray.filter(function(el) {
return getComputedStyle(el).display !== "none"
});
//and use length to count
var numberOfHiddenDivs = displayNone.length;
var numberOfVisibleDivs = displayShow.length;
alert("hidden:"+numberOfHiddenDivs+", visible:"+numberOfVisibleDivs);
#div-element > div{
width:100px;
height:50px;
border:1px solid gold;
background-color:red;
}
div.hide{
display:none;
}
<div id='div-element'>
<div class=hide></div>
<div class=hide></div>
<div class=hide></div>
<div></div>
<div></div>
<div></div>
<div class=hide></div>
<div></div>
<div class=hide></div>
<div></div>
<div style=display:none;></div>
<div style=display:none;></div>
</div>
While you are changing the visibility of specific div elements by document.getElementById('div-element').style.display = "none"; the count of visible and hidden elements can be easily performed by checking a "generated" style display attribute:
var countHidden = document.querySelectorAll("#div-element .dic-class[style='display: none;']").length;
var countVisible = document.querySelectorAll("#div-element .dic-class:not([style='display: none;'])").length;
Loop the items and then you can check the style by checking offsetParent , then push to an array.
var elem = document.querySelectorAll('#div-element .dic-class');
var visible = [];
for (i = 0; i < elem.length; i++) {
_this = elem[i];
if (_this.offsetParent !== null)
visible.push(elem[i]);
}
alert(visible.length);
#div-element {
display: none;
}
<div id="div-element">
<div class="dic-class"></div>
</div>
You can convert the NodeList into an array and then apply reduce to get the number of elements that don't have the display set to none inline:
var divs = Array.prototype.slice.call(document.querySelectorAll('#div-element .dic-class'));
console.log(divs.reduce(function(a, b){return a + (b.style.display != "none" ? 1 : 0)}, 0))
.dic-class {
display: inline-block;
margin: 5px;
height: 50px;
width: 50px;
background: green;
border: 1px solid black;
}
<div id="div-element">
<div class="dic-class"></div>
<div class="dic-class"></div>
<div class="dic-class" style="display: none"></div>
<div class="dic-class" style="display: none"></div>
<div class="dic-class"></div>
</div>
If you want to check for applies rules (not just inline ones), you can use getComputedStyle instead.
This is my first time using this forum and wow such good and fast replies.
I ended up using ChillNUT's code and the end result is this:
function IconCount() {
divs = document.querySelectorAll('#IconFX > div');
var divsArray = [].slice.call(divs);
var displayNone = divsArray.filter(function(el) {
return getComputedStyle(el).display === "none"
});
var displayShow = divsArray.filter(function(el) {
return getComputedStyle(el).display !== "none"
});
var numberOfHiddenDivs = displayNone.length;
var numberOfVisibleDivs = displayShow.length;
document.getElementById('VisibleIcons').innerHTML = numberOfVisibleDivs;
document.getElementById('HiddenIcons').innerHTML = numberOfHiddenDivs;
}
This way I can call this as a function when anything is hidden or visible and can interact with these output values with another script.
I have a CSS selector #menu li {background-color: red;}.
I want to access its attributes in JavaScript. It's important that I need to access both #menu and li since #menu alone has different attributes. It seems like getElementById(menu li), QuerySelector and getComputedStyle are not working in this case.
Is there any other way to achieve that or am I missing something here?
You should use jQuery for this, here the easy code example
//html
<div id="menu" data-number="123" >
</div>
//jquery
var menu = $('#menu').attr('data-number');
console.log(menu);
//print 123
jquery version
https://jsfiddle.net/pn52uvw1/
$(".button_1").click(function(){
alert($("#menu").attr("data-item-id"));
})
$(".button_2").click(function(){
alert($("#menu li").attr("data-item-id"));
})
non jquery version
https://jsfiddle.net/pn52uvw1/2/
window.firstFunction = function(){
var target = document.getElementById("menu");
alert(target.getAttribute('data-item-id'));
}
window.secondFunction = function(){
var target = document.getElementById("menu").children[0];
alert(target.getAttribute('data-item-id'));
}
but you will need to get rid of that [0] index probably, and use a for or something for multiple li items
If you want to get that css rule's property, you can do like this:
function getStyleFromSelector(selector, styleName) {
// Get all style elements
var styles = document.styleSheets;
var styleIndex = 0, styleCount = styles.length;
var rules, ruleCount, ruleIndex;
// Iterate though styles
for (styleIndex = 0; styleIndex < styleCount; ++styleIndex) {
// Get the css rules under the style.
rules = styles[styleIndex].rules;
ruleCount = rules.length;
for (ruleIndex = 0; ruleIndex < ruleCount; ++ruleIndex) {
// Check if the selector match the one we want
if (rules[ruleIndex].selectorText === selector) {
return styleName ?
rules[ruleIndex].style.getPropertyValue(styleName) : rules[ruleIndex];
}
}
}
}
var div = document.getElementById("results");
var result = getStyleFromSelector('#menu li');
console.log(result);
div.innerHTML = 'background-color is : ' + result.style.backgroundColor;
console.log(getStyleFromSelector('#menu li', 'background-color'));
#menu li {background-color: red;}
<div id="results"></div>
You can try it without additional Libraries with the following
var len = document.querySelectorAll("#menu li").length;
for(i = 0; i<len; i++)
document.querySelectorAll("#menu li")[i].style.backgroundColor="blue";
I also made you (a not very beautiful) jsfiddle
https://jsfiddle.net/gmeewsmz/
I need to check the display property of a header element on the page. Based on it different operations are to be done. I tried using
document.getElementsByTagName('header')[0].style.display
and comparing it to various display attributes, but this is executing false part whatever property I check for.
Here is my html :
<body>
<header id="main">
<p>Test to find the display property of an element (header in this case).</p>
</header>
</body>
And here is my Javascript :
var test1 = document.createElement('div');
var test2 = document.createElement('div');
test1.innerText = 'Testing for block : ';
test2.innerText = 'Testing for none : ';
var body = document.getElementById('main');
if (document.getElementsByTagName('header')[0].style.display == 'block') {
test1.innerText = test1.innerText + 'true part is executed';
body.appendChild(test1);
} else {
test1.innerText = test1.innerText + 'false part is executed';
body.appendChild(test1);
}
if (document.getElementsByTagName('header')[0].style.display == 'none') {
test2.innerText = test2.innerText + 'true part is executed';
body.appendChild(test2);
} else {
test2.innerText = test2.innerText + 'false part is executed';
body.appendChild(test2);
}
I put this also on jsfiddle http://jsfiddle.net/n8zDc/1/
What am I doing wrong ?
You want to use window.getComputedStyle. You haven't defined a display property value anywhere in the DOM
var header = document.getElementById('main');
var style = window.getComputedStyle(header);
console.log(style.display);
The reason is that .style doesn't really compute which style is actually applied to the element, but simply the style attribute on the DOM (either the HTML, or applied through JavaScript). As an example, consider this CSS:
* {
float: right;
}
.foo {
float: left;
}
And HTML:
<div>Foo</div>
<div class='foo'>Bar</div>
Neither of these have any style values in them, yet their computed styles will have a bunch of values, browser defaults such as display: block, and the CSS rules applied to them.
I have a series of p tags on my page and I want to wrap them all into a container, e.g.
<p>foo</p>
<p>bar</p>
<p>baz</p>
I want to wrap all the above tags into a container as follows:
<div>
<p>foo</p>
<p>bar</p>
<p>baz</p>
</div>
How to wrap a NodeList in an element using vanilla JavaScript?
Posted below are a pure JavaScript version of jQuery's wrap and wrapAll methods. I can't guarantee they work exactly as they do in jQuery, but they do in fact work very similarly and should be able to accomplish the same tasks. They work with either a single HTMLElement or an array of them. I haven't tested to confirm, but they should both work in all modern browsers (and older ones to a certain extent).
Unlike the selected answer, these methods maintain the correct HTML structure by using insertBefore as well as appendChild.
wrap:
// Wrap an HTMLElement around each element in an HTMLElement array.
HTMLElement.prototype.wrap = function(elms) {
// Convert `elms` to an array, if necessary.
if (!elms.length) elms = [elms];
// Loops backwards to prevent having to clone the wrapper on the
// first element (see `child` below).
for (var i = elms.length - 1; i >= 0; i--) {
var child = (i > 0) ? this.cloneNode(true) : this;
var el = elms[i];
// Cache the current parent and sibling.
var parent = el.parentNode;
var sibling = el.nextSibling;
// Wrap the element (is automatically removed from its current
// parent).
child.appendChild(el);
// If the element had a sibling, insert the wrapper before
// the sibling to maintain the HTML structure; otherwise, just
// append it to the parent.
if (sibling) {
parent.insertBefore(child, sibling);
} else {
parent.appendChild(child);
}
}
};
See a working demo on jsFiddle.
wrapAll:
// Wrap an HTMLElement around another HTMLElement or an array of them.
HTMLElement.prototype.wrapAll = function(elms) {
var el = elms.length ? elms[0] : elms;
// Cache the current parent and sibling of the first element.
var parent = el.parentNode;
var sibling = el.nextSibling;
// Wrap the first element (is automatically removed from its
// current parent).
this.appendChild(el);
// Wrap all other elements (if applicable). Each element is
// automatically removed from its current parent and from the elms
// array.
while (elms.length) {
this.appendChild(elms[0]);
}
// If the first element had a sibling, insert the wrapper before the
// sibling to maintain the HTML structure; otherwise, just append it
// to the parent.
if (sibling) {
parent.insertBefore(this, sibling);
} else {
parent.appendChild(this);
}
};
See a working demo on jsFiddle.
You can do like this:
// create the container div
var dv = document.createElement('div');
// get all divs
var divs = document.getElementsByTagName('div');
// get the body element
var body = document.getElementsByTagName('body')[0];
// apply class to container div
dv.setAttribute('class', 'container');
// find out all those divs having class C
for(var i = 0; i < divs.length; i++)
{
if (divs[i].getAttribute('class') === 'C')
{
// put the divs having class C inside container div
dv.appendChild(divs[i]);
}
}
// finally append the container div to body
body.appendChild(dv);
I arrived at this wrapAll function by starting with Kevin's answer and fixing the problems presented below as well as those mentioned in the comments below his answer.
His function attempts to append the wrapper to the next sibling of the first node in the passed nodeList. That will be problematic if that node is also in the nodeList. To see this in action, remove all the text and other elements from between the first and second <li> in his wrapAll demo.
Contrary to the claim, his function won't work if multiple nodes are passed in an array rather than a nodeList because of the looping technique used.
These are fixed below:
// Wrap wrapper around nodes
// Just pass a collection of nodes, and a wrapper element
function wrapAll(nodes, wrapper) {
// Cache the current parent and previous sibling of the first node.
var parent = nodes[0].parentNode;
var previousSibling = nodes[0].previousSibling;
// Place each node in wrapper.
// - If nodes is an array, we must increment the index we grab from
// after each loop.
// - If nodes is a NodeList, each node is automatically removed from
// the NodeList when it is removed from its parent with appendChild.
for (var i = 0; nodes.length - i; wrapper.firstChild === nodes[0] && i++) {
wrapper.appendChild(nodes[i]);
}
// Place the wrapper just after the cached previousSibling,
// or if that is null, just before the first child.
var nextSibling = previousSibling ? previousSibling.nextSibling : parent.firstChild;
parent.insertBefore(wrapper, nextSibling);
return wrapper;
}
See the Demo and GitHub Gist.
Here's my javascript version of wrap(). Shorter but you have to create the element before calling the function.
HTMLElement.prototype.wrap = function(wrapper){
this.parentNode.insertBefore(wrapper, this);
wrapper.appendChild(this);
}
function wrapDiv(){
var wrapper = document.createElement('div'); // create the wrapper
wrapper.style.background = "#0cf"; // add style if you want
var element = document.getElementById('elementID'); // get element to wrap
element.wrap(wrapper);
}
div {
border: 2px solid #f00;
margin-bottom: 10px;
}
<ul id="elementID">
<li>Chair</li>
<li>Sofa</li>
</ul>
<button onclick="wrapDiv()">Wrap the list</button>
If you're target browsers support it, the document.querySelectorAll uses CSS selectors:
var targets = document.querySelectorAll('.c'),
head = document.querySelectorAll('body')[0],
cont = document.createElement('div');
cont.className = "container";
for (var x=0, y=targets.length; x<y; x++){
con.appendChild(targets[x]);
}
head.appendChild(cont);
Taking #Rixius 's answer a step further, you could turn it into a forEach loop with an arrow function
let parent = document.querySelector('div');
let children = parent.querySelectorAll('*');
let wrapper = document.createElement('section');
wrapper.className = "wrapper";
children.forEach((child) => {
wrapper.appendChild(child);
});
parent.appendChild(wrapper);
* { margin: 0; padding: 0; box-sizing: border-box; font-family: roboto; }
body { padding: 5vw; }
span,i,b { display: block; }
div { border: 1px solid lime; margin: 1rem; }
section { border: 1px solid red; margin: 1rem; }
<div>
<span>span</span>
<i>italic</i>
<b>bold</b>
</div>