Get only visible element using pure javascript - javascript

I have elements like below
<div class="one">send Message</div>
<div class="one">send Message</div>
<div class="one">send Message</div>
I have a web page where there is send Message buttons like above, in which only one button is visible at a time.Other two buttons are hidden via some javascript codes.So for example if 2nd button is visible , I should be able to get only that element.
So my code will be something like
document.querySelector(".one:visible");
In jquery the code is $(".one:visible"); , which works fine , But I need to know how to do this via pure javascript.

Here's something you can use, pure Javascript:
// Get all elements on the page (change this to another DOM element if you want)
var all = document.getElementsByTagName("*");
for (var i = 0, max = all.length; i < max; i++) {
if (isHidden(all[i]))
// hidden
else
// visible
}
function isHidden(el) {
var style = window.getComputedStyle(el);
return ((style.display === 'none') || (style.visibility === 'hidden'))
}

I have something shorter:
Array.from(document.querySelectorAll('.one')).filter(s =>
window.getComputedStyle(s).getPropertyValue('display') != 'none'
);
Returns all elements with attribute display block set.

Use getBoundingClientRect. It will return height and width of zero if the element is not in the DOM, or is not displayed.
Note that this cannot be used to determine if an element is not visible due to visibility: hidden or opacity: 0. AFAIK this behavior is identical to the jQuery :visible "selector". Apparently jQuery uses offsetHeight and offsetWidth of zero to check for non-visibility.
This solution will also not check if the item is not visible due to being off the screen (although you could check that easily enough), or if the element is hidden behind some other element.
See also Detect if an element is visible (without using jquery)

var $el = document.querySelectorAll('.one');
var visibleElements;
for (var i = 0; i < $el.length; i++) {
var currentElement = $el[i];
var $style = window.getComputedStyle(currentElement, null);
if (!currentElement) {
return false;
} else if (!$style) {
return false;
} else if ($style.display === 'none') {
return false;
} else {
visibleElements.push(currentElement);
}
}
First we get all the elements using document querySelectorAll. Then, we need to iterate over all the elements. To get the style, use getComputedStyle.
After that :visible check only for display and we do it the same way.
A more comprehensive approach:
function isVisible(el) {
while (el) {
if (el === document) {
return true;
}
var $style = window.getComputedStyle(el, null);
if (!el) {
return false;
} else if (!$style) {
return false;
} else if ($style.display === 'none') {
return false;
} else if ($style.visibility === 'hidden') {
return false;
} else if (+$style.opacity === 0) {
return false;
} else if (($style.display === 'block' || $style.display === 'inline-block') &&
$style.height === '0px' && $style.overflow === 'hidden') {
return false;
} else {
return $style.position === 'fixed' || isVisible(el.parentNode);
}
}
}
This would check for any possible way an element could be visible in the dom to my knowledge minus the z-index cases.

If you're using the hidden attribute :
document.querySelector(".one:not([hidden])");

So all jQuery's :visible selector does is check the display property.
If that's all you want, this is all you'd need.
(window.getComputedStyle(el).getPropertyValue('display') !== 'none')
However, this is lacking in many use cases. If you seek a more comprehensive solution, keep reading.
Both Element.getBoundingClientRect() and window.getComputedStyle() are useful for determining if the element is visible and in the viewport.
You can't use getBoundingRect() alone to determine the visibility, and while you could use getComputedStyle() solely, it's not the optimal solution in terms of performance.
Both of these functions used in conjunction with each other is the best option (around 22% faster than getComputedStyle() alone.
function inViewport(els) {
let matches = [],
elCt = els.length;
for (let i=0; i<elCt; ++i) {
let el = els[i],
b = el.getBoundingClientRect(), c;
if (b.width > 0 && b.height > 0 &&
b.left+b.width > 0 && b.right-b.width < window.outerWidth &&
b.top+b.height > 0 && b.bottom-b.width < window.outerHeight &&
(c = window.getComputedStyle(el)) &&
c.getPropertyValue('visibility') === 'visible' &&
c.getPropertyValue('opacity') !== 'none') {
matches.push(el);
}
}
return matches;
}
With a usage example of...
var els = document.querySelectorAll('.one'),
visibleEls = inViewport(els);
This ensures that the display is not set to "none", the visibility is "visible", the width and height are greater than 0, and the element is within the bounds of the viewport.

Related

Javascript - add css style to element with class

I want to add only one css style in JS. I don't want to include jQuery for only one thing.
My code:
document.addEventListener('DOMContentLoaded', function() {
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
var productAttr = document.getElementsByClassName('product-attributes');
productAttr.style.top = "-90px";
}
});
The error from console is:
TypeError: 'undefined' is not an object (evaluating 'productAttr.style.top = "-90px"')
If I want change other styles f.e. opacity or color, I get the same problem.
How can I fix this ?
Thanks in advance for help.
You need to loop through your results because getElementsByClassName() returns a collection of elements:
for(var i = 0; i < productAttr.length; i++)
{
productAttr[i].style.top = "-90px";
}
Maybe it's because you can not give negative values in CSS
top:"-90px" === bottom "90px"
Maybe now it would work
document.addEventListener('DOMContentLoaded', function() {
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
var productAttr = document.getElementsByClassName('product-attributes');
productAttr.style.bottom = "90px";
}
});
It's preferred to have an id assigned to the targeted element then target using getElementById() as there cannot be elements with the same id, hence getElementByClassName() will return an array if there are multiple elements with the same className. If you need to target multiple elements, you should for-loop through them while applying the change to the nth item being looped:
for(x = 0; x < array.length; x++){
array[x].style.top = '-90px';
}
Gentle reminder: also remember to have position: relative|absolute|fixed to ensure 'top' attribute works
edited with thanks to Sebastien Daniel
When selecting a class you have to indicate what number is as an Tag, it is not like the id that there is only one.
It would be something like this code depending on which of the classes you want to apply it:
document.addEventListener('DOMContentLoaded', function() {
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
var productAttr = document.getElementsByClassName('product-attributes');
productAttr[0].style.top = "-90px";
productAttr[1].style.top = "-90px";
productAttr[2].style.top = "-90px";
}
});

finding if a particular div is invisible (visible = false) using javascript

using the below code i am finding if a div is invisible.
if(document.getelementbyid("header").style.visible){
alert("Yes");
}
else{
alert("No");
}
checking the visible property because in the code behind header.visible = false is defined depending upon the condition. But it always returning "No". Please tell the correct way.
There isn't a visible property, but visibility, and it can have the following values:
visible
hidden
collapse
See the MDN article.
You can use display and visibility to check if element is visible or not
var elem = document.getelementbyid("header");
if(elem .style.visibility == "hidden" || elem.style.display == 'none'){
alert("No"); // element is visible
}
else{
alert("Yes");
}
Remember that there is not style.visible in javascript. Depending on how do you hide a div, you need to check
if(document.getelementbyid("header").style.visibility != "hidden") {
//visible
} else {
//not visible
}
or
if(document.getelementbyid("header").style.display != "none") {
//visible
} else {
//not visible
}
At the same time, above code will only check if exact element has display none or visibility hidden. But at the same time, it will return visible when parent element is not visible. Because of that, you may do next:
var element = document.getelementbyid("header");
if(element.offsetWidth > 0 || element.offsetHeight > 0) {
//visible
} else {
//not visible
}
Browser always returns 0 width and height of an element if it is not visible
If you're using jQuery:
var isVisible = $("#header").is(":visible");
The CSS property is visibility. Bear in mind that the property may not contain the value you expect if it has been set using CSS, rather than by the style attribute.

how to detect if div is hidden by javascript

I have a DIV, that is sometimes hidden, and in this case I don't want that google adds appear/are loaded at all inside this DIV.
What is the best practice to make such a check with javascript?
You should look at the computed style of the node you want, via window.getComputedStyle, rather than the style attribute of the node, as css elsewhere may be effecting it too.
Checking whether a node is covered by another node is much more difficult, one way is to use document.elementFromPoint to find out which node is top-most at a specific point, then do this where your node should be until you're satisfied it's visible. For example, check the centre of the node is your node.
function isHidden(node, checkIfCovered) {
var absPosition = function absPosition(node) {
var x = 0, y = 0,
h = node.offsetHeight || 0, w = node.offsetWidth || 0;
do {
node.offsetLeft && (x = x + node.offsetLeft);
node.offsetTop && (y = y + node.offsetTop);
} while (node = node.offsetParent);
return {x: x, y: y, h: h, w: w};
},
o, style;
if (checkIfCovered && document.elementFromPoint) { // only if supported
o = absPosition(node); // get position & size
o.centre = {x: o.x + o.w / 2, y: o.y + o.h / 2}; // centre of node
if (document.elementFromPoint(o.centre.x, o.centre.y) !== node) {
return true; // another node is in the centre => covered
}
}
do { // loop up over parent nodes
if (node.nodeType === 9) break; // skip #document
style = window.getComputedStyle(node);
if ( style.display === 'none'
|| style.visibility === 'hidden'
|| style.opacity === '0'
) {
return true;
}
} while (node = node.parentNode);
// passed all tests, not hidden
return false;
}
Example usage
isHidden(document.getElementById('myDivId')); // true->hidden
isHidden(document.getElementById('myDivId'), true); // true->hidden or covered
Further things to consider
Is the node located where it is possible to scroll into view? See Fabrizio Calderan's comment.
Now edited in. Are the parent nodes hidden? You may want to loop up the DOM tree to find this out. It's okay if they are covered though, obviously. See Loïc Faure-Lacroix's comment.
if your div has an ID, try this:
if((document.getElementById('your_div_id').style.display=='none') || (document.getElementById('your_div_id').style.visibility=='hidden')){
//its hidden
}else{
//its not
}
you can check it by
var div = document.getElementById('div_id');
if( div.style.visibility=="hidden"
|| div.style.display=="none")
{ alert("div is hidden"); }
var isVisible = element.offsetWidth > 0 || element.offsetHeight > 0;
isVisible will give you is the div hidden or visible.
<script>
function isHidden(divId){
styleValue = document.getElementById(divId).style.display;
if(styleValue == 'none'){
return true;
}
else{
return false;
}
}
</script>
returnValue = isHidden(); //return true if hidden
There are a couple of ways to know if an object is hidden or not. There are couple of ways to find out but the truth is that it's much more complicated than most solution out there.
I can't unfortunately mash it up at the moment but I can tell how to do it.
An hidden object may still have display to something different than none or visibility to default. If parent objects are hidden, then child elements are also hidden but the display attributes remain unchanged.
In other word, you'll have to bubble every parent element until you find an hidden element or the root.
That said, css attributes like display and visibility isn't the only way to hide an element. You can also check for overflow: hidden and if the object is outside of the bounding box.
Pseudo code
def visible(initial, element)
if element.invisible or element.hidden
// Element was simply hidden so false
return false
if element != initial and elemen.has_overflow_hidden && initial.outside(element)
// Here we check if our element is inside the bounding box of a overflow hidden
// Parent.
return false
if element.opacity == 0
return false
if element == element.parent
// reached the root
return true
visible(initial, element.parent)
if (visible(element, element))
do something
else
do something else
As far as I can say, it's unfortunately not handling every cases. But it should be more than enough. It doesn't handle z-index, It might not work well with position absolute, relative and fixed.
In jquery:
$('#div').is(':visible');
$('#div').is(':hidden');
You're looking at the DOM elements (in this case) DIV, CSS property. There are two ways to hide an element.
One is display: none, the other is visibility: hidden.
In jQuery you would then do something like:
if !($('#div-id').css('display') == 'none'){
JAVASCRIPT_TO_LOAD_ADS_GOES_HERE
}
In the case of visibility hidden, do the same, but compare .css('visibility') to hidden.

Find element with specified z-index

How to find HTML element(-s) with z-index = 10 for example?
You have to iterate over all elements and check their z-index:
$('*').filter(function() {
return $(this).css('z-index') == 10;
}).each(function() {
// do something with them
});
One possible [jQuery] solution:
$(".elementsToSearch").each(function()
{
if($(this).css('z-index') == 10)
{
//then it's a match
}
});
Just loops through elements searching for a match to the css rule.
You can get all elements and filter them by css property:
$('*').each(function(){
if($(this).css('z-index') == 10) {
//$(this) - is element what you need
}
});
In my testing in Chrome 43, I found #ThiefMaster's post to be helpful, but not 100%. The value of the z-index being pulled was a string.
I also made this only iterate over visible elements and handle auto.
Here's my update:
var topZ = $('.thing-in-front').css('z-index')
if (topZ != 'auto') {
topZ = parseInt(topZ);
$('*:visible').filter(function() {
var thisZ = $(this).css('z-index')
return thisZ != 'auto' && parseInt(thisZ) >= topZ;
}).each(function() {
$(this).css('z-index', topZ - 1);
})
}
Without JQuery:
Array.from(document.querySelectorAll('*'))
.filter(e=>getComputedStyle(e).zIndex >= 0)

Check if element is empty of content, is a transparent container, blank

I need to check if an HTML element (any element will do) is empty of contents. By contents I don't mean text content or any other HTML elements, because that is already a given. I mean want to check if it's simply a blank element. For example:
If I hide the link, the only thing left is the paragraph element, which is now blank. It does not have any styles on it, so it's just a transparent container with margin/padding/whatever, but no other visual styles. Is there a way to detect this in Javascript? Any weird browser quirk will do. Ugly solutions valid too.
You want to recursively walk the childNodes of your element and check them to see if they are all blank. The recursive walking logic isn't difficult. It really all depends on how you define a blank element:
Display: none
Or visibility: hidden
Or all off the following criteria are true:
Text
None
or only whitespace
or text color is transparent
or text color is the same as the parent's background color
Background
Transparent
Matches parent
Border
Style: none
or width 0px
or color transparent
or color matches parent background
Tag
Not <img />
Children
none
or all satisfy above criteria
So, your recursive function would look something like this:
if (!window.getComputedStyle)
{
window.getComputedStyle = function(el)
{
return el.currentStyle || {};
};
}
function isElementBlank(el)
{
var style = window.getComputedStyle ? getComputedStyle(el, null) : el.currentStyle;
if (style.display == "none" || style.visibility == "hidden")
{
return true;
}
if (el.tagName.toLowerCase() == "img")
{
return false;
}
var parentBG = "transparent";
for (var parent = el.parentNode; parent; parent = parent.parentNode)
{
var parStyle = getComputedStyle(parent, null);
if (parStyle.backgroundColor != "transparent")
{
parentBG = parStyle.backgroundColor;
break;
}
}
if (style.backgroundColor != "transparent" && style.backgroundColor != parentBG)
{
return false;
}
if (style.borderColor != "transparent" &&
style.borderColor != parentBG &&
parseInt(style.borderWidth) > 0 &&
style.borderStyle != "none")
{
return false;
}
for (var i = 0; i < el.childNodes.length; i++)
{
var child = el.childNodes[i];
if (child.nodeType == 3)
{
if (/\S/.test(child.nodeValue) &&
style.color != parentBG &&
style.color != "transparent")
{
return false;
}
}
else if (!isElementBlank(child))
{
return false;
}
}
return true;
}
I didn't test this, but it's a start at least.
You could use a method where you remove all HTML and then trim the result.
If the result is empty string then there are no visible text.
This would not detect a div with height and background-color though so of you need that kind of detection you would also need to go over the while subtree looking for elements with any visible css which would require a very verbose code.
To detect empty-of-content tags you can iterate all child nodes of every nodes and looking for not empty text nodes. If a not empty text node is found the test pass, otherwise the node is an empty of content one. I've done a test that seems to works fine in Firefox:
<div id="container">
<div>Text <span>buzz</span>
</div>
<p>Hello
</p>
</div>
<script>
var all = document.getElementsByTagName('body')[0].getElementsByTagName('*');
allNodes: for (var i = 0, l = all.length; i < l; i++) {
// for each childNode of every node...
for (var ii = 0, sub = all[i].childNodes, ll = sub.length; ii < ll; ii++) {
// is it a text node?
if (sub[ii].nodeType == 3) {
// Is the text node NOT empty?
if (/[^\s]+/.test(sub[ii].nodeValue)) {
continue allNodes;
}
}
}
console.log(all[i], ' fails');
}
</script>
The test result is:
<div id="container"> fails
<p> fails

Categories

Resources