What is the best way in your experience to detect the existence of an element inside a div?
I'm currently using this:
if (($('.parentDiv').width()) > 0){
//Do something
}
There has to be a more elegant way.
If empty means not even text nodes:
if ($('.parentDiv').contents().length){
//Do stuff
}
or:
$('.parentDiv:not(:empty)') // which is nice...
.contents docs:
Description: Get the children of each element in the set of matched elements, including text and comment nodes.
if you care only of elements and not text nodes:
if ($('.parentDiv').children().length){
//Do stuff
}
Probably not what you want, but considering there's at least a little confusing over your requirements, you could consider if anything at all is within the container: elements, text, whatever.
Say you have an empty div:
<div class="parentDiv"></div>
Then $(".parentDiv").html().length == 0 indicates its emptiness.
If the div is not empty:
<div class="parentDiv"> </div>
<div class="parentDiv"><div></div></div>
Then $(".parentDiv").html().length will indicate its occupiedness (returning 1 and 11, respectively, in those scenarios.)
If you wish to check only for elements, or specific elements, then $(".parentDiv").children() would be the way to go.
Assuming you only care about elements (and not text nodes), you could check to see if the element has any children:
if($('.parentDiv').children().length) {
//Do stuff
}
Use the children() function
$('.parentDiv').children()
if ( $( '.parentDiv' ).children().length > 0 )
{
// do something
}
Related
This piece of code appears in a js script I have been asked to modify - I'm not sure why it is written in this way, it doesn't make sense to me.
Can anyone help explain what it is doing, and if it can be simplified to be a little more meaningful?
var unformathtml = $(this).text();
if(unformathtml.trim().length>showChar) {
$(this).parent().parent().parent().parent().parent().find('.comment-footer').fadeOut();
}
Lets' pretend we have a DOM like this:
<parent-5>
<target-element>Content</target-element>
<parent-4>
<parent-3>
<parent-2>
<parent-1>
<focused-element>Some Text</focused-element>
</parent-1>
</parent-2>
</parent-3>
</parent-4>
</parent-5>
What this code is saying is "if the text inside of <focused-element> has more characters than showChar then fade out <target-element>.
A better way of doing this would be to give <parent-5> some kind of identifier, which could be an ID or a class, and target that instead of the repeated .parent() call.
Here's an example which showcases the idea:
$('#oldMethod').click(function() {
$(this)
.parent()
.parent()
.parent()
.parent()
.parent()
.find('.comment-footer')
.toggleClass('red');
});
$('#newMethod').click(function() {
$(this)
.closest('.comment-container')
.find('.comment-footer')
.toggleClass('red');
});
.red {
color: #F00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="comment-container">
<div>
<div>
<div>
<div>
<button id="oldMethod">Old</button>
<button id="newMethod">New</button>
</div>
</div>
</div>
</div>
<div class="comment-footer">Footer</div>
</div>
Wow, that really doesn't make much sense. It is doing this:
1) Getting the raw contents out of an element
2) Checking to see if it is longer than a certain length
3) If so, fading out another element on the page
The parents() thing is very error-prone. It is going up a very precise number of levels in the HTML tree and then descending downwards to find an element with a class of '.comment-footer'. As a result a slight rearrangement of either element in the DOM might result in the code no longer working, because it can't find the specified element.
What you want is to find the tag-to-hide more directly. Ideally, the element-to-hide and the element-that-decides-to-hide would be next to eachother in the DOM (i.e. the element being hidden would be a child or sibling of the element that decides whether or not to hide it). This makes it very easy for the one to find the other. If that isn't possible, your next best bet would be to simply assign an id to the element you are trying to hide and then select on that id directly:
var unformathtml = $(this).text();
if(unformathtml.trim().length>showChar) {
$('#to_hide').fadeOut();
}
As a quick aside, .text() is used (instead of .html()), because the former removes any HTML tags. This way you are measuring the amount of "actual" text inside $(this) to determine whether or not you want to hide said element. So that part is probably fine.
You can do like if($('.div').find('.someelem').length == 0 .. to check whether .someelem is available inside the div,
but what if I want to check for any element? I don't know what is the class within.
<div>
</div>
^ Check above div contain something or not.
A faster way to do it is using .find() cause it will not trigger the somewhat expensive jQuery's Sizzle Selector Library:
if( !$(".div").find(">")[0] ){
// Maybe has text, but has absolutely no children Elements.
}
If you want to be more specific about your selectors, instead of using ">" (any immediate child) you can use "div" aswell, to restrict your search to DIV Elements only.
You can also check with "if is empty"
$(".div:empty").someMethodYouWant(); // Do some stuff on empty elements. (Really empty)
or
if( $(".div").is(":empty") ){
// Has no elements and no text
}
note that the above will yield false if you have just some text (means it's not empty).
If you rather want to go for immediate children > elements
if( !$(".div:has(>)").length ){
// Maybe has text, but has absolutely no children Elements.
}
or also:
if( !$(".div:has(>)")[0] ){
// Maybe has text, but has absolutely no children Elements.
}
or even simpler:
if( !$(".div >")[0] ){
// Maybe has text, but has absolutely no children Elements.
}
I've just started using jQuery, and can't get my head around this.
I need to check if a div contains anything but a h3 header tag.
The structure of the html is as follows:
<div id="myContainer">
<h3>A header that is always present</h3>
any html, plain text or empty
</div>
Here's the jQuery:
if ( $("#myContainer h3:only-child") ) {
$("#myContainer").css("display", "none");
}
The above will simply hide the div if there is no other html elements present, which is not what I intend since it will also contain plain text. I have tried with other selectors and functions, but I just can't seem to get it right.
Thanks in advance :)
I think you want a function which will tell you if the div contains just H3 or also has other elements. I don't think there is a direct jQuery selector for that, so I wrote a simple function to checkForJustH3.
DEMO - That shows how to hide div that just has H3.
Check out the below demo by editing the div contents and Hit Run to see the result.
DEMO
function containsJustH3 (el) {
var result = true;
$(el).contents().each (function() {
if (this.nodeName != 'H3') {
//check for blank line or empty spaces
if (this.nodeType == 3 && $.trim(this.nodeValue) == '') {
return true;
}
result = false;
return false;
}
});
return result;
}
And using the above function you can do something like,
if ( containsJustH3("#myContainer") ) {
$("#myContainer").css("display", "none");
}
Try:
$("#myContainer").children('h3').hide();
jsfiddle
You can wrap the 'plain text' in a p element and use this selector:
fiddle
$("#myContainer").children().not('h3').hide();
//Select all children but not the h3
HTML:
<div id="myContainer">
<h3>A header that is always present</h3>
<p>any html, plain text or empty</p>
</div>
You can use the length property to see how many children the div has
$("#myContainer").children('h3').length
The fundamental problem here is that jQuery methods like children will not get text nodes. If you want to see how many children a div has, and include the text nodes, you'll want to grab the actual dom node, and check the length of its childNodes property. This will include text nodes.
if ($("#myContainer")[0].childNodes.length > 1) {
var $cont=$('#myContainer'), $children=$cont.contents().not('h3');
if( ! $children.length) {
$cont.hide();
}
Using contents() method will check if there are tags or text nodes in element, check if the children object has length, if not hide the container
You can use $("#myContainer").contents().length to get the number of nodes, including text nodes. However, this includes the newline before the <h3>, etc.
I have a div set up something like this:
<div id="test"> <p>Hello</p> <p style="display: none">Goodbye</p> </div>
EDIT: To clarify, this is the simplest example. The div could have any arbitrary number of n deep nested children.
$('#test').getText() returns 'Hello Goodbye'. Here's a one liner to test in Firebug: jQuery('<div id="test"> <p>Hello</p> <p style="display: none">Goodbye</p> </div>').text()
This seems to be because what jQuery uses internally, textContent (for non IE), returns hidden elements as part of the text. Hrmph.
Is there a way to return the text content ignoring display:none'd elements? Basically I am trying to mimic the text you would get from highlighting the div with your mouse and copying to system clipboard. That ignores hidden text.
Interestingly, if you create a selection range and get the text from it, that also returns text inside display:none elements.
var range = document.body.createTextRange();
range.moveToElementText($('#test')[0]);
range.select();
console.log(range.toString()); // Also logs Hello Goodbye!
So creating a document selection range doesn't appear to do the same thing as highlighting with the mouse in terms of display:none elements. How do I get around this dirty pickle conundrum?
Edit: using .filter(':visible').text has been suggested, but it won't work for this scenario. I need the returned text to be EXACTLY what would come from a selection with the mouse. So for example:
$('<div>test1 <p>test2</p>\r\n <b>test3</b> <span style="display:none">none</span></div>').appendTo(document.body).children().filter(':visible').text()
returns
"test2test3"
When the output I actually want is
test1 test2
test3
linebreaks, whitespace and all, which come from the \r\n
Filter the elements using .filter(":visible").
Or use this:
$("#test :visible").text();
But the jQuery documentation advises us to use .filter() instead:
Because :visible is a jQuery extension and not part of the CSS specification,
queries using :visible cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. To achieve the best performance when using :visible to select elements, first select the elements using a pure CSS selector, then use .filter(":visible").
Use :visible in your selector as such:
$("#test > p:visible").text()
A Function example:
-- Edit:
http://jsfiddle.net/8H5ka/ ( Works on Chrome it displays "Hello" in Result )
If the above doesn't work:
http://jsfiddle.net/userdude/8H5ka/1/
If space isn't a major concern you could copy the markup, remove the hidden elements, and output that text.
var x = $('#test').clone();
x.filter(':not(:visible)').remove();
return x.text();
I had this problem and found this question, and it seems the actual solution is based on the provided answers but not actually written out. So here's a complete solution that worked for my situation, which is the same as the OP with the additional provision that elements may be invisible due to external styles based on DOM position. Example:
<style>.invisible-children span { display: none; }</style>
<div class="invisible-children">
<div id="test">Hello <span>Goodbye</span></div>
</div>
The solution is to:
Make a clone of the entire object.
Remove invisible objects in place; if we take #test out of the DOM before we remove invisible objects, jQuery might not know they're invisible because they will no longer match the CSS rules.
Get the text of the object.
Replace the original object with the clone we made.
The code:
var $test = $('#test');
// 1:
var $testclone = $test.clone();
// 2: We assume that $test is :visible and only remove children that are not.
$test.find('*').not(':visible').remove();
// 3:
var text = $test.text();
// 4:
$test.replaceWith($testclone);
// Now return the text...
return text;
// ...or if you're going to keep going and using the $test variable, make sure
// to replace it so whatever you do with it affects the object now in DOM and
// not the original from which we got the text after removing stuff.
$test = $testclone;
$test.css('background', 'grey'); // For example.
Here is how I did it with MooTools:
$extend(Selectors.Pseudo, {
invisible: function() {
if(this.getStyle('visibility') == 'hidden' || this.getStyle('display') == 'none') {
return this;
}
}
});
Element.implement({
getTextLikeTheBrowserWould = function() {
var temp = this.clone();
temp.getElements(':invisible').destroy();
return temp.get('text').replace(/ |&/g, ' ');
}
})
I search for that and found this question but without solution.
Solution for me is just get out of jquery to use DOM:
var $test = $('#test').get(0).innerText
or if more than on element in array of selector, you need a for loop and a merge but I guess that most of time it is the first version that you need.
var $test = $('#test').get().map(a => a.innerText).join(' ');
How do I check if $(this) is a div, ul or blockquote?
For example:
if ($(this) is a div) {
alert('its a div!');
} else {
alert('its not a div! some other stuff');
}
Something like this:
if(this.tagName == 'DIV') {
alert("It's a div!");
} else {
alert("It's not a div! [some other stuff]");
}
Solutions without jQuery are already posted, so I'll post solution using jQuery
$(this).is("div,ul,blockquote")
Without jQuery you can say this.tagName === 'DIV'
Keep in mind that the 'N' in tagName is uppercase.
Or, with more tags:
/DIV|UL|BLOCKQUOTE/.test(this.tagName)
To check if this element is DIV
if (this instanceof HTMLDivElement) {
alert('this is a div');
}
Same for HTMLUListElement for UL,
HTMLQuoteElement for blockquote
if(this.tagName.toLowerCase() == "div"){
//it's a div
} else {
//it's not a div
}
edit: while I was writing, a lot of answers were given, sorry for doublure
Going through jQuery you can use $(this).is('div'):
Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments.
Some of these solutions are going a bit overboard. All you need is tagName from regular old JavaScript. You don't really get any benefit from re-wrapping the whole thing in jQuery again, and especially running some of the more powerful functions in the library to check the tag name. If you want to test it on this page, here's an example.
$("body > *").each(function() {
if (this.tagName === "DIV") {
alert("Yeah, this is a div");
} else {
alert("Bummer, this isn't");
}
});
let myElement =document.getElementById("myElementId");
if(myElement.tagName =="DIV"){
alert("is a div");
}else{
alert("is not a div");
}
/*What ever you may need to know the type write it in capitalised letters "OPTIO" ,"PARAGRAPH", "SPAN" AND whatever */
I'm enhancing the answer of Andreq Frenkel, just wanted to add some and it became too lengthy so gone here...
Thinking about CustomElements extending the existing ones and still being able to check if an element is, say, input, makes me think that instanceof is the best solution for this problem.
One should be aware though, that instanceof uses referential equality, so HTMLDivElement of a parent window will not be the same as the one of its iframe (or shadow DOM's etc).
To handle that case, one should use checked element's own window's classes, something like:
element instanceof element.ownerDocument.defaultView.HTMLDivElement
Old question but since none of the answers mentions this, a modern alternative, without jquery, could be just using a CSS selector and Element.matches()
element.matches('div, ul, blockquote');
Try using tagName