Check if any childnodes exist using jquery / javascript - javascript

I have a DOM structure with div, p and span tags. I want to count the 'p' tags with children nodes and that without any children. I read a solution in this forum, but it doesn't work for me: How to check if element has any children in Javascript?.
Fiddle demo
$('#test').blur(function(){
var test= $('.check p').filter(function (){
if ($(this).childNodes.length > 0)
return this
});
alert(test.lenght)
})

it should be
$('#test').blur(function(){
var test= $('.check p').filter(function (){
return this.childNodes.length > 0; // as HMR pointed out in the comments if you are looking for child elements then $(this).children().length will do
})
alert(test.length)
})
Demo: Fiddle

Did you try this?
$('p:empty')
Should select all your empty p tags.
$('p').not(':empty')
Should select all your non empty p tags.

Here: http://jsfiddle.net/QN3aM/9/
$('#test').blur(function () {
var test = $('.check p').filter(function () {
return ($(this).children().length)
});
alert(test.length);
})
You just need to return true within filter, 0 is a falsey value and anything else will be truthy. also you spelt length wrong.
childNodes is a property of an element. as you were converting the element into a jquery object, you'd have to use the jquery method children()

Related

Select element by tag/classname length

I'd like to select an element using javascript/jquery in Tampermonkey.
The class name and the tag of the elements are changing each time the page loads.
So I'd have to use some form of regex, but cant figure out how to do it.
This is how the html looks like:
<ivodo class="ivodo" ... </ivodo>
<ivodo class="ivodo" ... </ivodo>
<ivodo class="ivodo" ... </ivodo>
The tag always is the same as the classname.
It's always a 4/5 letter random "code"
I'm guessing it would be something like this:
$('[/^[a-z]{4,5}/}')
Could anyone please help me to get the right regexp?
You can't use regexp in selectors. You can pick some container and select its all elements and then filter them based on their class names. This probably won't be super fast, though.
I made a demo for you:
https://codepen.io/anon/pen/RZXdrL?editors=1010
html:
<div class="container">
<abc class="abc">abc</abc>
<abdef class="abdef">abdef</abdef>
<hdusf class="hdusf">hdusf</hdusf>
<ueff class="ueff">ueff</ueff>
<asdas class="asdas">asdas</asdas>
<asfg class="asfg">asfg</asfg>
<aasdasdbc class="aasdasdbc">aasdasdbc</aasdasdbc>
</div>
js (with jQuery):
const $elements = $('.container *').filter((index, element) => {
return (element.className.length === 5);
});
$elements.css('color', 'red');
The simplest way to do this would be to select those dynamic elements based on a fixed parent, for example:
$('#parent > *').each(function() {
// your logic here...
})
If the rules by which these tags are constructed are reliably as you state in the question, then you could select all elements then filter out those which are not of interest, for example :
var $elements = $('*').filter(function() {
return this.className.length === 5 && this.className.toUpperCase() === this.tagName.toUpperCase();
});
DEMO
Of course, you may want initially to select only the elements in some container(s). If so then replace '*' with a more specific selector :
var $elements = $('someSelector *').filter(function() {
return this.className.length === 5 && this.className.toUpperCase() === this.tagName.toUpperCase();
});
You can do this in vanilla JS
DEMO
Check the demo dev tools console
<body>
<things class="things">things</things>
<div class="stuff">this is not the DOM element you're looking for</div>
</body>
JS
// Grab the body children
var bodyChildren = document.getElementsByTagName("body")[0].children;
// Convert children to an array and filter out everything but the targets
var targets = [].filter.call(bodyChildren, function(el) {
var tagName = el.tagName.toLowerCase();
var classlistVal = el.classList.value.toLowerCase();
if (tagName === classlistVal) { return el; }
});
targets.forEach(function(el) {
// Do stuff
console.log(el)
})

Loop through classes, and obtain their list item's innerHTML jQuery

There's an HTML page with 3 elements containing a class of ".list". Those ".list" elements have "li" elements in them, and in those "li" elements, there is text. I'd like to loop through all of "li" elements, and push their text to an array, with jQuery.
This is what I have so far:
var arr = [];
$(".list").each(function() {
this.children("li").each(function() {
arr.push(this.innerHTML);
});
});
However, I'm getting an error back from the console.
Error:
Uncaught TypeError: undefined is not a function
What am I doing wrong, and how can I fix it?
The value of this in your .each() loop will be a reference to an element, not a jQuery object. Thus:
$(".list").each(function() {
$(this).children("li").each(function() {
arr.push(this.innerHTML);
});
});
That is, $(this).children instead of this.children.
Note that you could avoid the outer .each() (not that there's anything terrible about it):
$(".list > li").each(function() {
arr.push(this.innerHTML);
});
Try following code. This will work for you
var arr = [];
var div = $(".list");
div.each(function() {
div.children("li").each(function() {
arr.push(this.innerHTML);
});
});
console.log(arr);

Get Inner HTML of Multiple Elements

I want to get the content of multiple Spans. Here is my code:
http://jsfiddle.net/4XumV/
It's supposed to give me "111, 222, 333, 444". It gives me "undefined" instead.
What's wrong with my code?
Well, you weren't actually getting the innerHTML property, you were getting an undefined html property. Change it to innerHTML and it will work.
http://jsfiddle.net/4XumV/1/
This should work:
$(function()
{
var allLatestNews = $("#main").find('span');
$.each(allLatestNews, function(i,val){
alert($(val).text());
});
});
I was wondering WHY your code wasn't working and JQuery does return an array of elements from the selector, this could have also worked:
for(var i = 0; i < allLatestNews.length; i++)
{
alert($(allLatestNews[i]).text());
}
First wrap the element as a JQuery object and then querying text() not html, which is accessed by a function not a property.
Your updated fiddle: http://jsfiddle.net/4XumV/9/
You seem to be confusing jquery's html with innerHTML.
You can either use innerHTML:
http://jsfiddle.net/4XumV/3/
alert(allLatestNews[i].innerHTML);
or jquery's html:
http://jsfiddle.net/4XumV/5/
alert(allLatestNews.eq(i).html());
Try this it should work
allLatestNews.each(function()
{
alert($(this).html());
});
var $elms = $('#main').find('span');
$elms.each(function(){ alert($(this).text()); });
http://jsfiddle.net/4XumV/2/
This is working
var allLatestNews = $("#main").find('span');
$.each(allLatestNews ,function( index , value){
console.log($(value).html());
});
instead of console.log($(value).html()); you can write alert($(value).html());
The property of a DOM element to return the inner HTML is named innerHTML not html
allLatestNews[i].innerHTML
Or using jQuery
$(allLatestNews[i]).html()
Updated JS Fiddle
you can also use this
var allLatestNews = $(this).find("#main span");
for(var i = 0; i < allLatestNews.length; i++)
{
alert(allLatestNews[i].innerHTML);
}

How to change text inside span with jQuery, leaving other span contained nodes intact?

I have the following HTML snippet:
<span class="target">Change me <a class="changeme" href="#">now</a></span>
I'd like to change the text node (i.e. "Change me ") inside the span from jQuery, while leaving the nested <a> tag with all attributes etc. intact. My initial huch was to use .text(...) on the span node, but as it turns out this will replace the whole inner part with the passed textual content.
I solved this with first cloning the <a> tag, then setting the new text content of <span> (which will remove the original <a> tag), and finally appending the cloned <a> tag to my <span>. This works, but feels such an overkill for a simple task like this. Btw. I can't guarantee that there will be an initial text node inside the span - it might be empty, just like:
<span class="target"><a class="changeme" href="#">now</a></span>
I did a jsfiddle too. So, what would be the neat way to do this?
Try something like:
$('a.changeme').on('click', function() {
$(this).closest('.target').contents().not(this).eq(0).replaceWith('Do it again ');
});
demo: http://jsfiddle.net/eEMGz/
ref: http://api.jquery.com/contents/
Update:
I guess I read your question wrong, and you're trying to replace the text if it's already there and inject it otherwise. For this, try:
$('a.changeme').on('click', function() {
var
$tmp = $(this).closest('.target').contents().not(this).eq(0),
dia = document.createTextNode('Do it again ');
$tmp.length > 0 ? $tmp.replaceWith(dia) : $(dia).insertBefore(this);
});
​Demo: http://jsfiddle.net/eEMGz/3/
You can use .contents():
//set the new text to replace the old text
var newText = 'New Text';
//bind `click` event handler to the `.changeme` elements
$('.changeme').on('click', function () {
//iterate over the nodes in this `<span>` element
$.each($(this).parent().contents(), function () {
//if the type of this node is undefined then it's a text node and we want to replace it
if (typeof this.tagName == 'undefined') {
//to replace the node we can use `.replaceWith()`
$(this).replaceWith(newText);
}
});
});​
Here is a demo: http://jsfiddle.net/jasper/PURHA/1/
Some docs for ya:
.contents(): http://api.jquery.com/contents
.replaceWith(): http://api.jquery.com/replacewith
typeof: https://developer.mozilla.org/en/JavaScript/Reference/Operators/typeof
Update
var newText = 'New Text';
$('a').on('click', function () {
$.each($(this).parent().contents(), function () {
if (typeof this.tagName == 'undefined') {
//instead of replacing this node with the replacement string, just replace it with a blank string
$(this).replaceWith('');
}
});
//then add the replacement string to the `<span>` element regardless of it's initial state
$(this).parent().prepend(newText);
});​
Demo: http://jsfiddle.net/jasper/PURHA/2/
You can try this.
var $textNode, $parent;
$('.changeme').on('click', function(){
$parent = $(this).parent();
$textNode= $parent.contents().filter(function() {
return this.nodeType == 3;
});
if($textNode.length){
$textNode.replaceWith('Content changed')
}
else{
$parent.prepend('New content');
}
});
Working demo - http://jsfiddle.net/ShankarSangoli/yx5Ju/8/
You step out of jQuery because it doesn't help you to deal with text nodes. The following will remove the first child of every <span> element with class "target" if and only if it exists and is a text node.
Demo: http://jsfiddle.net/yx5Ju/11/
Code:
$('span.target').each(function() {
var firstChild = this.firstChild;
if (firstChild && firstChild.nodeType == 3) {
firstChild.data = "Do it again";
}
});
This is not a perfect example I guess, but you could use contents function.
console.log($("span.target").contents()[0].data);
You could wrap the text into a span ... but ...
try this.
http://jsfiddle.net/Y8tMk/
$(function(){
var txt = '';
$('.target').contents().each(function(){
if(this.nodeType==3){
this.textContent = 'done ';
}
});
});
You can change the native (non-jquery) data property of the object. Updated jsfiddle here: http://jsfiddle.net/elgreg/yx5Ju/2/
Something like:
$('a.changeme3').click(function(){
$('span.target3').contents().get(0).data = 'Do it again';
});
The contents() gets the innards and the get(0) gets us back to the original element and the .data is now a reference to the native js textnode. (I haven't tested this cross browser.)
This jsfiddle and answer are really just an expanded explanation of the answer to this question:
Change text-nodes text
$('a.changeme').click(function() {
var firstNode= $(this).parent().contents()[0];
if( firstNode.nodeType==3){
firstNode.nodeValue='New text';
}
})
EDIT: not sure what layout rules you need, update to test only first node, otherwise adapt as needed

Recursion of .children() to search for id attribute

I'm new to jQuery, familiar with PHP & CSS. I have nested, dynamically generated div's which I wish to send (the id's) to a server-side script to update numbers for. I want to check everything in the .content class. Only div's with id's should be sent for processing; however I'm having trouble making a recursive children() check...this is the best (non-recursively) I could do:
$(".content").children().each(function() {
if ($(this).attr('id').length == 0) {
$(this).children().each(function() {
if ($(this).attr('id').length == 0) {
$(this).children().each(function() {
if ($(this).attr('id').length == 0) {
$(this).children().each(function() {
alert($(this).attr('id'));
});
}
});
}
});
}
});
and it just alert()'s the id's of everything at the level where they should be. There must be a better way to do this...thank you in advance for any advice.
-Justin
Try:
var ids = $('.content div[id]').map(function() {
return this.id;
}).get();
.content div[id] will select you all div descendants (at any level) of .content with non-empty ID attributes. The [id] part is an example of the Has Attribute selector.
I have used .map. to extract the IDs of the matches, and .get() to convert the resulting object into a basic array.
Try it here: http://jsfiddle.net/M96yK/
You can do:
$(".content div[id]");
This will return a jQuery object that contains all div's which have id's specified

Categories