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>
Related
<div class="pre-class">
<div>100%</div>
</div>
I'm trying to remove the percent (%) on the text inside the div after the class pre-class with textContent.replace("%","") but I just can't target that specific div
(I'm working on a longer website with a lot of divs and I can't add an ID to it because it's from a shortcode.)
I thought I could do something like this:
var textContent = document.getElementsByClassName('gamipress-progress-bar-completed').getElementsByTagName('div');
You're basically there. Don't forget that getElementsByClassname returns an array, so simply use [0] to retrieve the element. You'll see it working in the snippet below:
var textContent = document.getElementsByClassName('pre-class')[0].getElementsByTagName('div')[0].innerHTML;
console.log(textContent)
<div class="pre-class">
<div>100%</div>
</div>
You can use querySelector
let div = document.querySelector('div.pre-class > div');
div.innerText = div.innerText.replace('%', '')
<div class="pre-class">
<div>100%</div>
</div>
If the div will be the first direct child of the pre-class div, and you have one element with "pre-class" class, this will work
const textContent = document.querySelector('.pre-class').firstElementChild.textContent;
console.log(textContent.replace('%', ''))
<div class="pre-class">
<div>100%</div>
</div>
const content = document.querySelector('.pre-class > div').innerHTML;
content.replace("%", "");
<div class="pre-class">
<div>100%</div>
</div>
This is another way of selecting the div nested in your .pre-class div. Perhaps not the best way of doing this but it's handy to know querySelector works.
If you have lots of divs inside div.pre-class , its better to add specific data attribute to each child div and select the desired div using this:
< div class = 'pre-class' >
<div data-order = 'first' > 1 < /div>
<div data-order = 'second' > 2 < /div>
<div data-order = 'third' > 3 < /div>
</div>
///////////
document.querySelector('div[data-order="first"]')
let containers = document.getElementsByClassName("pre-class");
for (var i = 0; i<containers.length; i++) {
let current = containers[i];
let textNode = current.children[0];
textNode.innerText = textNode.innerText.replace(/(\d)%/, '$1');
};
<div class="pre-class">
<div>100%</div>
</div>
Alternatively, you could use element.querySelector() (or querySelectorAll) to find the correct element(s) to replace.
let textNode = document.querySelector(".pre-class > div"); // use querySelectorAll in case there can be multiple matches.
textNode.innerText = textNode.innerText.replace(/(\d)%/, '$1');
<div class="pre-class">
<div>100%</div>
</div>
Use the child selector (>).
let textDiv=document.querySelector(".pre-class > div");
textDiv.textContent=textDiv.textContent.replace("%","");
This will replace the first direct div inside .pre-class. You can adjust the position of divs using pseudo classes. Like for example, if you want to select the second div inside .pre-class, you would use:
<div class="pre-class">
<div>100%</div>
<div>200%</div>
<div>300%</div>
</div>
let textDiv=document.querySelector(".pre-class > div:nth-child(2)");
textDiv.textContent=textDiv.textContent.replace("%","");
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>
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
I have a bunch of span4 class elements in my html. they look something like this:
<div class="span4">
<div class="widget">
<div class="header">blablabla</div>
</div>
</div>
I want to sort the span4 by that text iside header class.
I do this to sort them
$(".span4").sort(sortAlpha)
but how do I select the text inside the header class?
I'm doing this but I guess there is a better way
function sortAlphaAsc(a,b){
var nomeA = $(a.childNodes[1].childNodes[1]).text();
var nomeB = $(b.childNodes[1].childNodes[1]).text();
return a.innerHTML.toLowerCase() > b.innerHTML.toLowerCase() ? 1 : -1;
};
there must be a better way than
$(a.childNodes[1].childNodes[1]).text()
var elems = $(".span4");
elems.sort(function(a, b) {
return $(a).find('.header').text().toUpperCase().localeCompare(
$(b).find('.header').text().toUpperCase()
);
});
$(".span4").parent().html(elems);
FIDDLE
Try this:
function sortAlphaAsc(a,b){
var nomeA = $(a).find('div.header').text();
var nomeB = $(b).find('div.header').text();
return nomeA.toLowerCase() > nomeB.toLowerCase();
};
You could detach the spans, sort and append them.
That will be very fast too as changing elements in memory and only updating the DOM once in the end is very efficient.
var $spans = $(".span4").detach();
var sortedSpans = $spans.sort(function(spanA, spanB) {
var spanTextA = $("div.header", spanA).text();
var spanTextB = $("div.header", spanB).text();
return spanTextA > spanTextB;
});
$("body").append(sortedSpans);
Obviously instead of body you append it back to it's actual container element.
Or if the spans are in a common container store the parent in cache var $parent = $spans.parent() and in the end simply do $parent.html(sortedSpans).
I don't know your whole mark-up but that should get you started.
DEMO - Detach spans, sort them and append again
Do you mean something like this:
$('.span4').find('.header').text();
This will return the text inside the header div.
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;
});