I feel like this could have been asked before, but I can't seem to find it, so I'll ask myself.
I want to select the parent element that is the "cause" of its children being hidden. For example, a group of elements are essentially "hidden" but not because they have display:none but because some parent along the way has display:none.
If I only have a child element and I know that it is hidden, how might I easily find the parent that is causing it to be hidden.
I realize one solution is just to recursively loop through the parents such as...
function findHiddenParent(el){
var $el = $(el);
if($el.css('display') == 'none'){
return $el;
}
return findHiddenParent($el.parent());
}
Note I haven't tested the above code, its just for conceptualizing a solution
But is there an easier way, perhaps through some selector magic?
You can use .parents() then filter that to the last element that is hidden.
$(child).parents(":hidden").last().show();
it will select the parent element highest in the hierarchy that has display: none
Demo: http://jsfiddle.net/X9W2v/
Note, :hidden will also select elements with a width/height of 0.
Here's something similar to what you've got:
function findHiddenParents ( el ) {
return $(el).parents().filter(function () {
return $(this).css('display') == 'none';
});
}
This'll return all ancestors that are hidden. If you only want the closest or the farthest, you can just return it with .first() or .last() respectively.
If you're not actually interested in which elements are hidden, but just want to reveal them all, then you can't get any simpler than this:
$(el).parents().show()
This is how I would do it in plain JavaScript. Somehow I feel it's cleaner than the jQuery solutions that involve loops or callbacks (Kevin B's one-liner looks great!). The cons are, it's longer, and it doesn't check computed styles:
<div id="container">
<div id="a" style="display: none;">A
<div id="b">B
<div id="c">C</div>
</div>
</div>
</div>
var currentNode = document.getElementById('c');
while(currentNode.parentNode && currentNode.style.display !== 'none') {
currentNode = currentNode.parentNode;
}
alert(currentNode.id);
http://jsfiddle.net/nc4h2/
Related
I am developing a game that glitches at some point through using the CSS filter: invert(1); property. However, when you use that property on body, it makes everything position: absolute;. This is not good because I need most elements to be fixed, and everything goes to a negative top and not visible. How can I effectively get all elements in a list that isn't a parent to any other elements, but included if it has text? Any answers or other stack overflow topics would be nice!
Here is some of my code:
// In a working loop called Repeat()
if(Glitch == 1) {
document.querySelector(".ChangableStyles").innerHTML = "* {filter: invert(1)}"
} else {
document.querySelector(".ChangableStyles").innerHTML = ""
}
Edit: Since all of you are asking, the .ChangableStyles tag is a style element. The filter on everything applies when I change the innerHTML of that style tag to valid CSS styles. I don't want to be rude, but I have the .ChangableStyles thing figured out. Thank you.
You mention you already have a list of elements, but it's not clear how you're generating that list. I've gone ahead on the assumption you're wanting to "select" all elements in <body></body> that don't have any children.
You can use a combination of Array.from(), your pre-existing selection logic, and a filter() using node.childElementCount === 0 to accomplish what you describe. However on higher-complexity DOMs this will be computationally expensive, so I would implore you to re-consider your design instead of opting for this route. To be clear, this will meet your requirement of selecting ANY Node in the DOM which has no child elements ("isn't a parent to any other elements"), which includes any script, style or other "user-invisible" nodes in the body.
document.getElementById('get-elements-button').addEventListener('click', function () {
console.log(Array.from(document.body.getElementsByTagName("*")).filter(function (node) {
return node.childElementCount === 0;
}));
});
<div class="has-child-elements">
This is a child element
</div>
<div class="has-no-child-elements">
</div>
<div class="has-child-elements">
This is also a child element
</div>
<button id='get-elements-button'>Get elements with child elements →</button>
Right now I have a a bootstrap row set up with a checkbox and input inside of it.
<div class="row">
<div class="AdminFees">
<div class="col-md-2"><input type="checkbox" class="make-switch feeswitch" data-on-color="info" data-off-color="info" data-on-text="Yes" data-off-text="No" name="HasPerMemberFee" checked="#Model.Contract.HasPerMemberFee" /></div>
</div>
<div class="col-md-2"><input type="text" class="form-control" placeholder="$0.00" id="PerMemberFeeAmount" name="PerMemberFeeAmount" value="#Model.Contract.PerMemberFeeAmount" /></div>
I have 6 or 7 very identical field pairs that I am manipulating generically so I don't have to make multiple functions. I am having trouble figuring out how to reference the text input element from the checkbox element.
Jquery:
$('.feeswitch').each(function () {
$(this).on('switchChange.bootstrapSwitch', function () {
if ($(this).bootstrapSwitch('state') == true)
$(this).next('input').css('visibility', 'visible');
else
$(this).next('input').css('visibility', 'hidden');
});
});
I have tried next and nextAll, but to my understanding, those only find child elements. I need to know how to select the child of the second adjacent parent element.
In an attempt to simplify the situation:
The checkbox has 2 parents, the two divs, and 1 adjacent element, the other div column. I need to access the child of that other div column, but it needs to be generically so I don't need to make 8 functions for each checkbox/input pair on my page.
I'm not sure I agree that the accepted solutions is stable, since it's selector greatly depends on keeping your structure the same, which I would suggest is unlikely in most projects. If I might suggest an alternative, I think the better method here is to employ the scope parameter of the selector.
$('.feeswitch').on('switchChange.bootstrapSwitch', function () {
var switchState = $(this).bootstrapSwitch('state') ? "visible" : "hidden";
$('input',$(this).closest('.row')).not($(this)).css('visibility', switchState);
});
Regardless, you should definitely look more in to jQuery DOM traversal methods, as that's pretty much the big magic of jQuery:
https://api.jquery.com/category/traversing/
You'll want to say something like:
$(this).parent().parent().next('div').find('input').
css('visibility', 'visible');
And since this is generic, you don't need the each():
$('.feeswitch').on('switchChange.bootstrapSwitch',
function () {
var visi = $(this).bootstrapSwitch('state') ? 'visible' : 'hidden';
$(this).parent().parent().next('div').find('input').
css('visibility', visi);
}
);
I need to use jQuery to locate all DIV tags that have no attributes on them and apply a class to each. Here's a sample HTML:
<div id="sidebar">
<div>Some text goes here</div>
<div class="something">something goes here</div>
<div>Another div with no attributes.</div>
</div>
So, I need to take that and turn it into this:
<div id="sidebar">
<div class="myClass">Some text goes here</div>
<div class="something">something goes here</div>
<div class="myClass">Another div with no attributes.</div>
</div>
How do you locate elements of type div that have no attributes via jQuery? Thanks.
Here you go:
$('div', '#sidebar').filter(function () {
return this.attributes.length === 0;
})
Live demo: http://jsfiddle.net/phbU9/
The attributes property returns a list of all attributes set on the element. "Naked" elements have an empty attributes list.
Update: Be sure to read Tim's answer below which provides a solution for older versions of IE, since my own solution doesn't work in IE8 and below.
#Šime's answer is close but doesn't work in IE 6, 7 or 8, where an element's attributes collection has an entry for every possible attribute, not just those specified in the HTML. You can get round this by checking each attribute object's specified property.
Live demo: http://jsfiddle.net/timdown/6MqmK/1/
Code:
$("div").filter(function() {
var attrs = this.attributes, attrCount = attrs.length;
if (attrCount == 0) {
return true;
} else {
for (var i = 0; i < attrCount; ++i) {
if (attrs[i].specified) {
return false;
}
}
return true;
}
});
check this out:
http://jsfiddle.net/thilakar/CHux9/
You need to give some sort of selector, in this case Ive used your side bar but it can be anything. Then get the children that have no class attribute and add a new class. See JSFiddle for the example:
http://jsfiddle.net/HenryGarle/q3x5W/
$("#sidebar").children('div:not([class])').addClass('newClass');
So this would return the 2 elements with no class tag and leave the sidebar and div with the class completely unaffected.
You could use a combination of jQuery's has attribute selector and the not selector. For example:
$('div:not([class], [id])').addClass('myClass');
jsFiddle demonstrating this
With this approach, you need to explicitly specify the attributes to check the presence of. Sime's solution would apply the class to divs that do not have any attributes at all.
To expound upon Tim Down's answer, I recommend checking that the attrs var not null special cases where the html has comment tags, etc.
try $('div:not([class])').addClass('myClass');
it is a general approach because the class will apply to all the div that have no class
$('#sidebar div')` or more general `$('div'); //returns collections of divs
to answer the question:
$('#sidebar div').addClass('myClass');
In jQuery, we can easily get the CSS value for a given element with the css method:
$('#myElement').css('line-height'); // e.g. '16px'
Now, since this CSS value might have been inherited from a parent element, is there any way to know which element has this rule applied to it?
For example, let's say I have the following HTML:
<div class="parent">
<div id="myElement"></div>
</div>
and the following CSS:
.parent {
line-height: 20px;
}
Calling the css method on #myElement will return 20px, but it will not indicate that it was inherited from .parent.
I know I can just fire up Web Inspector/Dev Tools/Firebug, but I want to get it programmatically.
Is this at all possible?
Walk up the parentElement chain checking the css() value of each element. The first element with a parent().css() value that's different is (probably) the element being targeted by the CSS rule selector.
See this fiddle for an example: http://jsfiddle.net/broofa/VPWV9/2/ (See the console.log output)
(Note: there are almost surely complex cases where this won't work as expected but for the case as described, it works.)
I have a similar solution to broofa's. It also has the same problem though.
Here's the fiddle:
http://jsfiddle.net/2w3kt/
$.fn.getStyleParent = function(property)
{
var $source = this.get(0), // only do for 1st element :P
srcVal = $source.css(property),
$element = null;
$(this).parents().each(function()
{
var $this = $(this);
if( $this.css(property) == srcVal )
element = $this;
else
return false; // stops the loop
});
return $element;
}
I have a collection of elements on my page, and I want to see if they are visible or not currently.
So:
$(".someClass")
How can I loop through and figure this out? because if it is visible, i have to fire another function.
$(".someClass").each(function(){
if($(this).is(":visible")){
//item is visible: do something
}
});
how about that?
$(".someClass:visible")
will return the visible ones.
What you could do:
$(".someClass").each(function(x) { if ( x.style.display != "none" && x.style.visibility != "hidden" ) { your_function(); } });
where your_function() is the name of your function.
All solutions in terms of $('.someClass').is(':visible') are unreliable. All it tells us is if a particular element has a styling of display:none or visibility:hidden. This is not the same as whether an element is visible!
Consider a situation like this:
<div style="display:none;"><div class="someClass"></div></div>
Everybody can see that the element designated by $('.someClass') is invisible. But $('.someClass').is(':visible') will return true!
The only water-proof solution is to not only check for is(':visible') on the $('.someClass'), but on all of its parent elements as well. Only if for none of the parents holds that is(':visible') === false, we can conclude that $('.someClass') is actually visible.