Is there a JS/jQuery Fully Recursive child node count function? - javascript

Folks,
Let's say that I have the following situation:
<div class="outer">
<div>
<span>
<ul>
<div> </div>
<div> </div>
</ul>
</span>
</div>
</div>
How would I find the total number of elements inside div.outer? Something like $('div.outer').children().size() or length returns 1 (I'm looking, in this case, for 5) is there a shortcut or function to find the total element count using js/jQuery or should I write a function just for this issue? TIA.

var totalDescendants = $('div.outer *').length;
and done.
var totalDescendants = $('div.outer').find('*').length;
would also work.

A simple (and likely faster than jQuery) JavaScript alternative would be
var el = document.getElementById("foo");
var descendantElementCount = el.getElementsByTagName("*").length;
This does assume you've given the element an id. You could use jQuery to get all the elements with class outer, if this is important:
var descendantElementCount = 0;
$('div.outer').each(function() {
descendantElementCount += this.getElementsByTagName("*").length;
});

jQuery recursive child node count function:
jQuery(document).ready(function(){
var totalChildren=jQuery("*","div.outer").length;
});

Related

Javascript - Strip certain strings from ".innerHTML" result

I have a function that's run on a button click. This function will get all of the HTML inside a certain element. That works fine. However, I would like to clean the returned string (HTML) up before using it further in my function:
exportHTML(){
const element = document.getElementById('content');
const innerHTML = element.innerHTML;
}
This works. But due to using Angular, Angular syntax is included within the HTML based on conditions in the source code. For example:
<div _ngcontent-c1=""></div>
OR
<div ng-reflect-klass="panel album"></div>
<div ng-reflect-ng-class="blue"></div>
Is it at all possible to filter these types of values out? In regards to the second and third example above, the classes within those would change quite often:
Is it possible to filter out and remove all _ngcontent-c1="" text
Is it possible to filter out and remove all ng-reflect-klass & ng-reflect-ng-class including the following open and closed quotes (to remove what's inside)
OK, so the attributes would be constant but the values of the attributes would change? If so, you could try this:
.replace(/ng-reflect-klass=\".?\"/,"").replace(/ng-reflect-ng-class=\".?\"/,"").replace(/_ngcontent-c1=\".*?\"/,"")
var content = 'stuff<div ng-reflect-klass="panel album"></div><div ng-reflect-ng-class="blue"></div><div _ngcontent-c1=""></div>end stuff';
console.log(content.replace(/ng-reflect-klass=\".*?\"/g,"").replace(/ng-reflect-ng-class=\".*?\"/g,"").replace(/_ngcontent-c1=\".*?\"/g,""));
Look at the console to view the result.
You could do it with RegExp
const innerHTML = element.innerHTML.replace(/ (_ngcon|ng-).*?".*?"/g, '');
(_ngcon|ng-) find _ngcon or ng- including space as first character
.*?" match everything until first "
.*?" and match everything again for the closing "
I created a JSFiddle as an example of how to do this without using jQuery.
Using the HTML code below as an example
<div id="origin-content">
<div id="div1" _ngcontent-c1="">Content 1</div>
<div id="div2" ng-reflect-klass="panel album">Content 2</div>
<div id="div3" ng-reflect-ng-class="blue">Content 3</div>
</div>
<hr>
<div id="target-content">
</div>
I extracted all children from origin-content and copied them to target-content using the code that follows.
var result = document.getElementById('target-content');
var elems = document.querySelector('#origin-content').children;
var count = elems.length;
for (var i = 0; i < count; i++) {
var val = elems[i];
val.removeAttribute('_ngcontent-c1');
val.removeAttribute('ng-reflect-klass');
val.removeAttribute('ng-reflect-ng-class');
result.innerHTML += val.outerHTML;
}
There is still plenty of room for improvement.
I hope it helps to solve the OP question.
The following solution will remove all the attributes from element:
You can get all the children first. Then loop through them with forEach(). In each iteration, you can use while loop to removeAttribute() until they are exist in the element.
Try the following way:
function exportHTML(){
const element = document.getElementById('content');
const innerHTML = [].slice.call(element.children);
innerHTML.forEach(function(el){
while(el.attributes.length > 0)
el.removeAttribute(el.attributes[0].name);
});
console.log(document.getElementById('content').innerHTML); // output
}
exportHTML();
<div id="content">
<div _ngcontent-c1=""></div>
<div ng-reflect-klass="panel album"></div>
<div ng-reflect-ng-class="blue" another-test></div>
<span test="test-element"></span>
</div>

A function to remove specified elements

I need to create a function which gets user input (a css selector) and removes all of those elements.
This is the function so far
function removeBySelector(selector) {
var thisOne = document.querySelectorAll(selector);
for(var i = 0; i<thisOne.length; i++) {
document.removeChild(thisOne[0]);
};
};
and the HTML that starts it
<button type="button" name="button" onclick="removeBySelector(prompt('Type the selector e.g p/ p.pClass'));">Remove By Selector</button>
change your method to
function removeBySelector(selector)
{
var thisOne = document.querySelectorAll(selector);
for(var i = 0; i<thisOne.length; i++)
{
thisOne[i].parentNode.removeChild( thisOne[i] ); //changed parentElement to parentNode
};
}
i'd advise using the framework jQuery! It is a very powerful tool that helps you simplify and improve your JavaScript code and it's performance.
With jQuery you can easily use this piece of code to remove any elements by CSS selector.
// Use any CSS Selector here
var elements = $(".class");
$.each(elements, function(){
$(this).remove();
)};
This keeps your code very easy to read and has a high performance.
//Try this code:
var removeElement=function(selector){
$(document).find(selector).remove();
};
removeElement('h1'); // will remove all H1 elements from Document.
You can do the same, without using any library with pure javascript (ES6 syntax in this case):
let elements = document.querySelectorAll(".please-remove");
elements.forEach(e => e.remove());
<div>
<div class="keep">Keep this element</div>
<div class="please-remove">1</div>
<div class="please-remove">2</div>
<div class="please-remove">3</div>
<div class="please-remove">4</div>
<div class="please-remove">5</div>
<div class="please-remove">6</div>
</div>

count of dynamically created DIVs returning zero

Following is my code and relevant HTML , what i wanna do is that i wanna count the number of search-img-box within search-img-ctrl but i get 0 as output, just to tell here that
following div search-img-box is dynamically created.
jQuery(document).ready(function() {
var numberOfDivs = jQuery('#search-img-ctrl').filter('.search-img-box').length;
alert(numberOfDivs);
});
following is my HTML
<div id="search-img-ctrl" class="search-img-ctrl">
<div id="search-img-box" class="search-img-box" name="search-img-box">
<img width="335" height="206" src="" alt="">
<ul>
</div>
<div id="search-img-box" class="search-img-box" name="search-img-box">
</div> </div>
Here's a fiddle: http://jsfiddle.net/t5jcT/
I changed filter to find and got rid of the duplicate ids in the html.
jQuery(document).ready(function() {
var numberOfDivs = jQuery('#search-img-ctrl').find('.search-img-box').length;
alert(numberOfDivs);
});
or you can use selectors instead of the find as others have pointed out:
jQuery(document).ready(function() {
var numberOfDivs = jQuery('#search-img-ctrl .search-img-box').length;
alert(numberOfDivs);
});
use .find instead of .filter:
var numberOfDivs = jQuery('#search-img-ctrl').find('.search-img-box').length;
alert(numberOfDivs);
If you want to only find the number of direct children with that class you can use .children
var numberOfDivs = jQuery('#search-img-ctrl').children('.search-img-box').length;
Also make sure you edit your html so that your html elements don't have duplicate IDs

How can I remove wrapper (parent element) without removing the child?

I would like to remove the parent without removing the child - is this possible?
HTML structure:
<div class="wrapper">
<img src"">
</div>
<div class="button">Remove wrapper</div>
After clicking on the button I would like to have:
<img src"">
<div class="button">Remove wrapper</div>
Pure JS (ES2015) solution, in my opinion easier to read than jQuery-solutions.
node.replaceWith(...node.childNodes)
Node has to be an ElementNode
const wrapperNode = document.querySelector('h1')
wrapperNode.replaceWith(...wrapperNode.childNodes)
<h1>
<a>1</a>
<b>2</b>
<em>3</em>
</h1>
Pure JS solution that doesn't use innerHTML:
function unwrap(wrapper) {
// place childNodes in document fragment
var docFrag = document.createDocumentFragment();
while (wrapper.firstChild) {
var child = wrapper.removeChild(wrapper.firstChild);
docFrag.appendChild(child);
}
// replace wrapper with document fragment
wrapper.parentNode.replaceChild(docFrag, wrapper);
}
Try it:
unwrap(document.querySelector('.wrapper'));
Surprised that nobody's posting the simplest answer:
// Find your wrapper HTMLElement
var wrapper = document.querySelector('.wrapper');
// Replace the whole wrapper with its own contents
wrapper.outerHTML = wrapper.innerHTML;
Could use this API: http://api.jquery.com/unwrap/
Demo http://jsfiddle.net/7GrbM/
.unwrap
Code will look something on these lines:
Sample Code
$('.button').click(function(){
$('.wrapper img').unwrap();
});
Pure javascript solution, i'm sure someone can simplify it more but this is an alternative for pure javascript guys.
HTML
<div class="button" onclick="unwrap(this)">Remove wrapper</div>
Javascript (pure)
function unwrap(i) {
var wrapper = i.parentNode.getElementsByClassName('wrapper')[0];
// return if wrapper already been unwrapped
if (typeof wrapper === 'undefined') return false;
// remmove the wrapper from img
i.parentNode.innerHTML = wrapper.innerHTML + i.outerHTML;
return true;
}
JSFIDDLE
if you're using jQuery:
$(".wrapper").replaceWith($(".wrapper").html());
If the wrapper element contains text, the text remains with child nodes.

Selecting second children of first div children in javascript [duplicate]

This question already has answers here:
querySelector with nested nth-child in Chrome doesn't appear to work
(2 answers)
Closed 3 years ago.
I have an html that look something like this:
<div id="mainDiv"> <-- I have this
<div>
<div></div>
<div></div> <-- I need to get this
</div>
<span></span>
<more stuff />
</div>
i am using:
var mainDiv = document.getElementById('mainDiv');
because I need that div in a var, but i also need to get that second div on the first div inside mainDiv into a variable.
How could I do it in a simple cross-browser way?
Assuming that structure is static you can do this:
var mainDiv = document.getElementById('mainDiv'),
childDiv = mainDiv.getElementsByTagName('div')[0],
requiredDiv = childDiv.getElementsByTagName('div')[1];
Further reading: .getElementsByTagName() (from MDN).
var mainDiv = document.getElementById('mainDiv');
var x = mainDiv.children[0].children[1];
or
var mainDiv = document.getElementById('mainDiv');
var x = mainDiv.getElementsByTagName('div')[0].getElementsByTagName('div')[1];
I would go simply with just one line of vanilla code.
Works for any elements, is not limited to the tag names you have in the structure. But the number of elements and the hierarchy must be preserved.
var requiredDiv = document.getElementById('mainDiv').firstChild.firstChild.nextSibling;
I would pick jQuery and end up with something like this:
var getThis = $('#mainDiv > div:eq(0) > div:eq(1)');
Fiddle
var mainDiv = document.getElementById('mainDiv');
var div = maindiv.getElementsByTagName('div')[2];//third div
http://jsfiddle.net/MGVw8/
You know there is querySelector now ?
console.log(
mainDiv.querySelector(':nth-child(1) > :nth-child(2)'))
<div id="mainDiv">
<div>
<div></div>
<div>come get me</div>
</div>
<!-- more stuff -->
</div>

Categories