Reason for doing that: I'm debugging css of my webpage.. some elements appeared and they're not supposed to appear. I suspect it is the issue with element positioning.. therefore I want to find these positioned element and check one by one.
This one is using jQuery. I hope you are find with it.
var find = $('*').filter(function () {
return $(this).css('position') == 'fixed';
});
I think this one works using a pure javascript:
var elems = document.body.getElementsByTagName("*");
var len = elems.length
for (var i=0;i<len;i++) {
if (window.getComputedStyle(elems[i],null).getPropertyValue('position') == 'fixed') {
console.log(elems[i])
}
}
Here is an ES6 version that gives you an array of these elements for further processing:
let fixedElements = [...document.body.getElementsByTagName("*")].filter(
x => getComputedStyle(x, null).getPropertyValue("position") === "fixed"
);
document.querySelector('*[style="position:fixed"]')
The * item specifies all tag names. The [] indicate that you're looking for an attribute. You want your style attribute to have position:fixed.
If you aren't using jQuery, this is probably going to be your simplest option.
Warnings that apply to all answers:
This is a slow operation. On a large-enough page, this operation can take 100ms or more, which is a lot for a single operation. You shouldn't need this unless you're developing a browser extension.
Now sticky elements can act as fixed elements in some cases
Having said that, here's the shortest and most efficient version to do this:
const fixed = [].filter.call(document.all, e => getComputedStyle(e).position == 'fixed');
Here's a version that includes sticky elements, but they're not exactly equivalent, it depends on what you're looking for:
const all = [].filter.call(
document.all,
e => ['fixed', 'sticky'].includes(getComputedStyle(e).position)
);
If you're feeling modern, replace document.all with document.querySelectorAll('*'), but the former will likely work forever.
Try this:
var elements = $('*').filter(function () {
return this.style.position == 'fixed';
});
It will give you all elements having position fixed.
Related
I have my own implementation of dropdown list. I am storing all list identifiers in the global array and on window click event I am iterating through this array and deciding which list I have to hide.
I need to check if element has ancestor with .active class.
jQuery version:
for (var i = 0; i < window.dropdowns.length; i++) {
var e = window.dropdowns[i];
if ($(event.target).closest('.active').length == 0) {
e.hideList();
}
}
Pure javascript version:
for (var i = 0; i < window.dropdowns.length; i++) {
var e = window.dropdowns[i];
var parent = event.target.parentElement;
while (parent.tagName != 'BODY') {
if (parent.className.indexOf('active') > 0) {
e.hideList();
break;
}
parent = parent.parentElement;
}
}
So, what version of this will be faster? And how performance depends on number of elements on the page?
If you just want to know what's fastest, write a simple test to find out. If you want to know why...
jQuery is going to do more work than you need, for example, you are only testing tagName and className.
Having said that, your code could give you false positives because className.indexOf('active') will return > -1 if the element has a class of notactive. Use classList instead.
Finally, if you are already using jQuery, you should use it since we just showed you that code we write ourselves can be buggy, and performance is not likely to matter in this case.
Remember, premature optimization is the root of a lot of spaghetti code.
If you were interested in knowing hard numbers, you could turn your loops into functions and use console.time and console.timeEnd on them. Something like this:
//First while loop
console.time(firstWhileLoopInFunction)
console.timeEnd(firstWhileLoopInFunction)
//Second while loop
console.time(secondWhileLoopInFunction)
console.timeEnd(secondWhileLoopInFunction)
contenteditable div
((grade >= passingMark) && (grade<101))
HTML
<span class="cond frag">(<span class="cond frag">(grade >= passingMark)</span> && <span class="cond frag">(grade<101)</span>)</span>
How would i know if i am the last child of cond or there is no next sibling following me (grade<101)
Something like (in a loop):
$elem = $('.frag').eq(fragNum);
if ($elem.nextAll('.cond').length === 0 ) {
alert('last child detected');
}
If by "How would i know ..." you mean "In JavaScript, how would I get..."
MooTools makes it easy:
var last = document.getElement('.cond').getLast('span');
In this case, document.getElement will get the first element that matches .cond in document.
There will be a simple jQuery equivalent too.
If you are using native JS, you run into problems as there is no native support for "getElemntByClassName" in IE<9. There are a bunch of frameworks and tools to bridge these browser gaps like MooTools, JQuery, Prototype, etc, but if you need native and know the index position of the span with class .cond within a specific container, you could try:
var conds = document.getElementsByTagName("span")[0].getElementsByTagName("span");
var last = conds[conds.length-1];
Where document is your specific container and 0 is the position (first in container).
If this is the only problem you would like to solve, there is this 2008 "getElementsByClassName" solution that still works nicely is IE<9 by Robert Nyman - http://robertnyman.com/2008/05/27/the-ultimate-getelementsbyclassname-anno-2008/
Do you mean something like this?
http://jsfiddle.net/KyleMuir/nujr7/1/
var elements = document.getElementsByClassName('cond');
var totalElements = elements.length;
var lastElement = elements[totalElements -1];
Added console.logs to illustrate this clearer in the fiddle.
Hope this helps.
How can I select nodes that begin with a "x-" tag name, here is an hierarchy DOM tree example:
<div>
<x-tab>
<div></div>
<div>
<x-map></x-map>
</div>
</x-tab>
</div>
<x-footer></x-footer>
jQuery does not allow me to query $('x-*'), is there any way that I could achieve this?
The below is just working fine. Though I am not sure about performance as I am using regex.
$('body *').filter(function(){
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
Working fiddle
PS: In above sample, I am considering body tag as parent element.
UPDATE :
After checking Mohamed Meligy's post, It seems regex is faster than string manipulation in this condition. and It could become more faster (or same) if we use find. Something like this:
$('body').find('*').filter(function(){
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
jsperf test
UPDATE 2:
If you want to search in document then you can do the below which is fastest:
$(Array.prototype.slice.call(document.all)).filter(function () {
return /^x-/i.test(this.nodeName);
}).each(function(){
console.log(this.nodeName);
});
jsperf test
There is no native way to do this, it has worst performance, so, just do it yourself.
Example:
var results = $("div").find("*").filter(function(){
return /^x\-/i.test(this.nodeName);
});
Full example:
http://jsfiddle.net/6b8YY/3/
Notes: (Updated, see comments)
If you are wondering why I use this way for checking tag name, see:
JavaScript: case-insensitive search
and see comments as well.
Also, if you are wondering about the find method instead of adding to selector, since selectors are matched from right not from left, it may be better to separate the selector. I could also do this:
$("*", $("div")). Preferably though instead of just div add an ID or something to it so that parent match is quick.
In the comments you'll find a proof that it's not faster. This applies to very simple documents though I believe, where the cost of creating a jQuery object is higher than the cost of searching all DOM elements. In realistic page sizes though this will not be the case.
Update:
I also really like Teifi's answer. You can do it in one place and then reuse it everywhere. For example, let me mix my way with his:
// In some shared libraries location:
$.extend($.expr[':'], {
x : function(e) {
return /^x\-/i.test(this.nodeName);
}
});
// Then you can use it like:
$(function(){
// One way
var results = $("div").find(":x");
// But even nicer, you can mix with other selectors
// Say you want to get <a> tags directly inside x-* tags inside <section>
var anchors = $("section :x > a");
// Another example to show the power, say using a class name with it:
var highlightedResults = $(":x.highlight");
// Note I made the CSS class right most to be matched first for speed
});
It's the same performance hit, but more convenient API.
It might not be efficient, but consider it as a last option if you do not get any answer.
Try adding a custom attribute to these tags. What i mean is when you add a tag for eg. <x-tag>, add a custom attribute with it and assign it the same value as the tag, so the html looks like <x-tag CustAttr="x-tag">.
Now to get tags starting with x-, you can use the following jQuery code:
$("[CustAttr^=x-]")
and you will get all the tags that start with x-
custom jquery selector
jQuery(function($) {
$.extend($.expr[':'], {
X : function(e) {
return /^x-/i.test(e.tagName);
}
});
});
than, use $(":X") or $("*:X") to select your nodes.
Although this does not answer the question directly it could provide a solution, by "defining" the tags in the selector you can get all of that type?
$('x-tab, x-map, x-footer')
Workaround: if you want this thing more than once, it might be a lot more efficient to add a class based on the tag - which you only do once at the beginning, and then you filter for the tag the trivial way.
What I mean is,
function addTagMarks() {
// call when the document is ready, or when you have new tags
var prefix = "tag--"; // choose a prefix that avoids collision
var newbies = $("*").not("[class^='"+prefix+"']"); // skip what's done already
newbies.each(function() {
var tagName = $(this).prop("tagName").toLowerCase();
$(this).addClass(prefix + tagName);
});
}
After this, you can do a $("[class^='tag--x-']") or the same thing with querySelectorAll and it will be reasonably fast.
See if this works!
function getXNodes() {
var regex = /x-/, i = 0, totalnodes = [];
while (i !== document.all.length) {
if (regex.test(document.all[i].nodeName)) {
totalnodes.push(document.all[i]);
}
i++;
}
return totalnodes;
}
Demo Fiddle
var i=0;
for(i=0; i< document.all.length; i++){
if(document.all[i].nodeName.toLowerCase().indexOf('x-') !== -1){
$(document.all[i].nodeName.toLowerCase()).addClass('test');
}
}
Try this
var test = $('[x-]');
if(test)
alert('eureka!');
Basically jQuery selector works like CSS selector.
Read jQuery selector API here.
Using jQuery I can easily get the number of DOM elements used by a web page:
$('*').length;
But not all web sites are using jQuery.
So my question is: How do I get the number of DOM elements used in a web page using pure JavaScript and js console.
Assuming you mean "HTMLElementNodes" as opposed to "All nodes" (which would include such things as text nodes and also be skipped by your jQuery example) then:
document.getElementsByTagName('*').length
This still requires the use of DOM though. Pure JavaScript can't interact with an HTML document other than as a string of text.
It's quite simple really:
document.getElementsByTagName('*').length
If you can ignore older browsers, you could also preserve some of the jQuery-like syntax with:
var $;
$ = document.querySelectorAll.bind(document);
$('*').length;
This question is the top result on google for "js count all dom nodes" but it's 2021 now and we have ShadowDOM so none of these previous answers will actually give an accurate result.
Better to use this function which is based on the code used by Lighthouse to calculate the true DOM size.
function countNodes(element = document.body) {
let count = 0; let child = element.firstElementChild;
while (child) { count += countNodes(child);
if (child.shadowRoot) { count += countNodes(child.shadowRoot); }
child = child.nextElementSibling; count++;
} return count;
}
Using a recursive function countChildrenNumber:
function countChildrenNumber(el) {
let result = 0
if (el.children && el.children.length > 0) {
result = result + el.children.length
for (let i = 0; i < el.children.length; i++) {
result = result + countChildrenNumber(el.children[i])
}
}
return result
}
then call it by passing document as the parameter
countChildrenNumber(document)
The main answer doesn't really count everything (I think shadow DOM would be excluded)
Using snippet below works better for me:
$$('*').length
Is it possible to use HTML and/or Javascript to automatically work out what the next page anchor is and go to it?
Reading your comment to Calgary Coder, I believe - if I understand you correctly - you're looking to find out the anchor in the current URL. You can do this with window.locaiton.hash. E.g.
alert(window.location.hash);
Thanks for the answers everyone, but I managed to get this working by implementing http://marcgrabanski.com/articles/scrollto-next-article-button-jquery. This works by going to the next header, rather than the next anchor but I imagine if it's critical to use anchors it could be easily adapted to do so.
Assuming you mean relative to a known anchor/item; if you are using jQuery, they have a selector for "Next Sibling"; find the documentation here:
http://api.jquery.com/next-siblings-selector/
I am just running out; otherwise I would build up the full selector for you, but if you don't have an answer later today, I will put it together.
Edit
Actually, based on further reading, I am quessing you are looking for the next anchor relative to the current scroll position on the page... that is a little more work... but is doable... (again, I will try to get on later today to provide the JS).
Edit
These are not 100% complete; but should be enough so you get the general idea. If your page is static content, I would recommend going through the page and caching all offsets on document ready; determining an elements offset can be pretty slow (especially in older browsers).
var _anchorOffets = {};
$(document).ready(function () {
$("A[id]:not(A[href])").each(function (index, value) {
var $anchor = $(value);
_anchorOffets[$anchor.attr("id")] = $anchor.offset().top;
});
});
function getNextAnchorId() {
var $window = $(window);
var minOffset = $window.scrollTop() + $window.height();
for (var anchor in _anchorOffets) {
if (_anchorOffets[anchor] >= minOffset) {
return anchor;
}
}
return null;
}
alternatively, if you page has dynamic content and the anchor locations are not fixed within the document, then you would be looking at something closer to
function getNextAnchorId() {
var result = null;
$("A[id]:not(A[href])").each(function (index, value) {
var $anchor = $(value);
var $window = $(window);
var minOffset = $window.scrollTop() + $window.height();
if($anchor.offset().top >= minOffset) {
result = $anchor.attr("id");
return false;
}
});
return result;
}
Depending on your page, you may need to expand on this idea. Both of the above solutions assume a pretty basic document layout. If you have anything fancy going on with relative/absolute positing, or scrollable divs etc, you will need to beef this up (I can provide code if that is the case). For now though I am assuming that we are talking about a basic find the anchors on the page, and figure out which anchor would be next based on scroll position. Also, I didn't extensively test, so some polish may also be required :D
I think I understand what you're looking for. If you know the id's you can use this...
function Next(){
var lnkNext = document.getElementById("yourNextAnchorId");
window.location.href = lnkNext.src;
}
if you don't know the id's maybe get the anchors by the innerText