If you were to label elements by some [tag] system, likely attached by the user, and you wanted to count the number of tags (defined by the number of classes the element has), how would you accomplish this?
This could be beneficial if you were to try to review all elements by number of tags. (This likely could be accomplished by other structures, but if you were to only reference the element tags in this way)
Jquery has .hasClass(), is there something like .classCount()
You could create it...
$.fn.classCount = function() {
return $.grep(this.attr("class").split(/\s+/), $.trim).length;
};
jsFiddle.
If you don't have jQuery, you could use...
var classLength = element.classList.length;
jsFiddle.
If you don't have jQuery and have to support the older browsers, go with...
var classes = element.className.replace(/^\s+|\s+$/g, "").split(/\s+/);
var classLength = classes[0].length ? classes.length : 0;
jsFiddle.
You can use the classList attribute if you are using HTML5. For example
$("#someElementId").classList.length
would return 2 for:
<div id="someElementId" class="stinky cheese"></div>
as in http://jsfiddle.net/thegreatmichael/rpdEr/
$(element).attr('class').split(/\s+/).length
jsFiddle example
Related
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.
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.
I'm trying to highlight rows in a table using jQuery, but I'm wondering if it's possible to use a variable for the row I want highlighted. This is the code I have now, which is not working.
var rowNumber = 3 //I want to use a loop, but for testing purposes I have it set to 3
$('tr:eq(rowNumber)').addClass('highlight');
Sure, why not. You may pass a variable in :eq() selector:
$("tr:eq(" + rowNumber + ")").addClass("highlight");
or use eq() method instead:
$("tr").eq(rowNumber).addClass("highlight");
$('tr').eq(rowNumber).addClass('highlight');
Should work for you.
Let me first address isolated access (i.e. not taking into consideration optimisation for loops)
Best solution: Use .eq() (fast, nice and short)
You could try something like
$('tr').eq(rowNumber).addClass('highlight');
Explanation: .eq(index) Reduces the set of matched elements to the one at the specified index.
Source: http://api.jquery.com/eq/
Alternative solution: Use the ":eq(index)" selector (unnecessarily slower, more verbose and convoluted)
$("tr:eq("+rowNumber+")").addClass('highlight');
A third solution: (fast, but more verbose than the proposed solution)
$($('tr').get(rowNumber)).addClass('highlight');
How this one works: $('tr').get(rowNumber) gets the (rowNumber+1)th DOM element matching the query selector and then this is wrapped in jQuery goodness using the surrounding $( ).
More info at: http://api.jquery.com/get/
Feel free to experiment with the accompanying jsFiddle:
http://jsfiddle.net/FuLJE/
If you are particularly performance conscious and are indeed are going to iterate through an array you can do this instead:
var trs = $('tr').get(); //get without arguments return the entire array of matched DOM elements
var rowNumber, len = trs.length;
for(rowNumber = 0; rowNumber < len; rowNumber++) {
var $tr = $(trs[rowNumber]);
//various stuff here
$tr.addClass('highlight');
//more stuff here
}
Of course you could also use .each()
$("tr").each(function (rowNumber, tr) {
var $tr = $(tr);
//various stuff here
$tr.addClass('highlight');
//more stuff here
})
Documentation can be found here: http://api.jquery.com/each/
Just to point out the obvious: $("tr").addClass('highlight') would work if adding the highlight class to all tr was all that the OP wanted to do :-)
I want to be able to get the first matching element, then the second, and so on, for the following CSS selector:
[att]
The below selectors are not valid CSS3 selectors, but that is what I'm trying to accomplish:
[att][0]
[att][1]
...
[att][n]
Can I combine multiple selectors and iterate over each matching node just like the example above?
[att1],[att2]
If this can't be done with native DOM or CSS3 selectors, then an XPath query is also an option.
If document.querySelectorAll() is an option, it will be very easy — just pass the selector and the browser will handle the rest:
var elms = document.querySelectorAll('[att]');
for (var i = 0; i < elms.length; ++i) {
alert(elms[i].tagName);
}
It works with any CSS selector you pass it provided the browser supports it (which in this case any browser implementing the function should already do). So to pick elements that have either att1, att2 or both, use this as mentioned in the comments:
var elms = document.querySelectorAll('[att1], [att2]');
Using jQuery:
$('[att]');
Also, this works:
$('[att1],[att2]');
The first will give you a list of all elements with an att attribute. If you don't want to use jQuery, your code will run much slower since the logical way to do this is:
var elems = document.getElementsByTagName('*');
for(var i=0, l=elems.length; i<l; i++){
if(elems[i].getAttribute('att')){
// do stuff
}
}
The reason jQuery is actually faster is because it will use XPath queries or other methods when possible, which will greatly speed up the execution. Of course you could implement XPath in the above code if you want.
I'm refactoring some old JavaScript code and there's a lot of DOM manipulation going on.
var d = document;
var odv = d.createElement("div");
odv.style.display = "none";
this.OuterDiv = odv;
var t = d.createElement("table");
t.cellSpacing = 0;
t.className = "text";
odv.appendChild(t);
I would like to know if there is a better way to do this using jQuery. I've been experimenting with:
var odv = $.create("div");
$.append(odv);
// And many more
But I'm not sure if this is any better.
Here's your example in the "one" line.
this.$OuterDiv = $('<div></div>')
.hide()
.append($('<table></table>')
.attr({ cellSpacing : 0 })
.addClass("text")
)
;
Update: I thought I'd update this post since it still gets quite a bit of traffic. In the comments below there's some discussion about $("<div>") vs $("<div></div>") vs $(document.createElement('div')) as a way of creating new elements, and which is "best".
I put together a small benchmark, and here are roughly the results of repeating the above options 100,000 times:
jQuery 1.4, 1.5, 1.6
Chrome 11 Firefox 4 IE9
<div> 440ms 640ms 460ms
<div></div> 420ms 650ms 480ms
createElement 100ms 180ms 300ms
jQuery 1.3
Chrome 11
<div> 770ms
<div></div> 3800ms
createElement 100ms
jQuery 1.2
Chrome 11
<div> 3500ms
<div></div> 3500ms
createElement 100ms
I think it's no big surprise, but document.createElement is the fastest method. Of course, before you go off and start refactoring your entire codebase, remember that the differences we're talking about here (in all but the archaic versions of jQuery) equate to about an extra 3 milliseconds per thousand elements.
Update 2
Updated for jQuery 1.7.2 and put the benchmark on JSBen.ch which is probably a bit more scientific than my primitive benchmarks, plus it can be crowdsourced now!
http://jsben.ch/#/ARUtz
Simply supplying the HTML of elements you want to add to a jQuery constructor $() will return a jQuery object from newly built HTML, suitable for being appended into the DOM using jQuery's append() method.
For example:
var t = $("<table cellspacing='0' class='text'></table>");
$.append(t);
You could then populate this table programmatically, if you wished.
This gives you the ability to specify any arbitrary HTML you like, including class names or other attributes, which you might find more concise than using createElement and then setting attributes like cellSpacing and className via JS.
I'm doing like that:
$('<div/>',{
text: 'Div text',
class: 'className'
}).appendTo('#parentDiv');
Creating new DOM elements is a core feature of the jQuery() method, see:
http://api.jquery.com/jQuery/#creating-new-elements
and particulary http://api.jquery.com/jQuery/#example-1-1
since jQuery1.8, using $.parseHTML() to create elements is a better choice.
there are two benefits:
1.if you use the old way, which may be something like $(string), jQuery will examine the string to make sure you want to select a html tag or create a new element. By using $.parseHTML(), you tell jQuery that you want to create a new element explicitly, so the performance may be a little better.
2.much more important thing is that you may suffer from cross site attack (more info) if you use the old way. if you have something like:
var userInput = window.prompt("please enter selector");
$(userInput).hide();
a bad guy can input <script src="xss-attach.js"></script> to tease you. fortunately, $.parseHTML() avoid this embarrassment for you:
var a = $('<div>')
// a is [<div></div>]
var b = $.parseHTML('<div>')
// b is [<div></div>]
$('<script src="xss-attach.js"></script>')
// jQuery returns [<script src="xss-attach.js"></script>]
$.parseHTML('<script src="xss-attach.js"></script>')
// jQuery returns []
However, please notice that a is a jQuery object while b is a html element:
a.html('123')
// [<div>123</div>]
b.html('123')
// TypeError: Object [object HTMLDivElement] has no method 'html'
$(b).html('123')
// [<div>123</div>]
UPDATE
As of the latest versions of jQuery, the following method doesn't assign properties passed in the second Object
Previous answer
I feel using document.createElement('div') together with jQuery is faster:
$(document.createElement('div'), {
text: 'Div text',
'class': 'className'
}).appendTo('#parentDiv');
Though this is a very old question, I thought it would be nice to update it with recent information;
Since jQuery 1.8 there is a jQuery.parseHTML() function which is now a preferred way of creating elements. Also, there are some issues with parsing HTML via $('(html code goes here)'), fo example official jQuery website mentions the following in one of their release notes:
Relaxed HTML parsing: You can once again have leading spaces or
newlines before tags in $(htmlString). We still strongly advise that
you use $.parseHTML() when parsing HTML obtained from external
sources, and may be making further changes to HTML parsing in the
future.
To relate to the actual question, provided example could be translated to:
this.$OuterDiv = $($.parseHTML('<div></div>'))
.hide()
.append($($.parseHTML('<table></table>'))
.attr({ cellSpacing : 0 })
.addClass("text")
)
;
which is unfortunately less convenient than using just $(), but it gives you more control, for example you may choose to exclude script tags (it will leave inline scripts like onclick though):
> $.parseHTML('<div onclick="a"></div><script></script>')
[<div onclick="a"></div>]
> $.parseHTML('<div onclick="a"></div><script></script>', document, true)
[<div onclick="a"></div>, <script></script>]
Also, here's a benchmark from the top answer adjusted to the new reality:
JSbin Link
jQuery 1.9.1
$.parseHTML: 88ms
$($.parseHTML): 240ms
<div></div>: 138ms
<div>: 143ms
createElement: 64ms
It looks like parseHTML is much closer to createElement than $(), but all the boost is gone after wrapping the results in a new jQuery object
var mydiv = $('<div />') // also works
var div = $('<div/>');
div.append('Hello World!');
Is the shortest/easiest way to create a DIV element in jQuery.
I've just made a small jQuery plugin for that: https://github.com/ern0/jquery.create
It follows your syntax:
var myDiv = $.create("div");
DOM node ID can be specified as second parameter:
var secondItem = $.create("div","item2");
Is it serious? No. But this syntax is better than $("<div></div>"), and it's a very good value for that money.
I'm a new jQuery user, switching from DOMAssistant, which has a similar function: http://www.domassistant.com/documentation/DOMAssistantContent-module.php
My plugin is simpler, I think attrs and content is better to add by chaining methods:
$("#container").append( $.create("div").addClass("box").html("Hello, world!") );
Also, it's a good example for a simple jQuery-plugin (the 100th one).
It's all pretty straight forward! Heres a couple quick examples...
var $example = $( XMLDocRoot );
var $element = $( $example[0].createElement('tag') );
// Note the [0], which is the root
$element.attr({
id: '1',
hello: 'world'
});
var $example.find('parent > child').append( $element );
What about this, for example when you want to add a <option> element inside a <select>
$('<option/>')
.val(optionVal)
.text('some option')
.appendTo('#mySelect')
You can obviously apply to any element
$('<div/>')
.css('border-color', red)
.text('some text')
.appendTo('#parentDiv')
Not mentioned in previous answers, so I'm adding working example how to create element elements with latest jQuery, also with additional attributes like content, class, or onclick callback:
const mountpoint = 'https://jsonplaceholder.typicode.com/users'
const $button = $('button')
const $tbody = $('tbody')
const loadAndRender = () => {
$.getJSON(mountpoint).then(data => {
$.each(data, (index, { id, username, name, email }) => {
let row = $('<tr>')
.append($('<td>', { text: id }))
.append($('<td>', {
text: username,
class: 'click-me',
on: {
click: _ => {
console.log(name)
}
}
}))
.append($('<td>', { text: email }))
$tbody.append(row)
})
})
}
$button.on('click', loadAndRender)
.click-me {
background-color: lightgrey
}
<table style="width: 100%">
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Email</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<button>Load and render</button>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
jQuery out of the box doesn't have the equivalent of a createElement. In fact the majority of jQuery's work is done internally using innerHTML over pure DOM manipulation. As Adam mentioned above this is how you can achieve similar results.
There are also plugins available that make use of the DOM over innerHTML like appendDOM, DOMEC and FlyDOM just to name a few. Performance wise the native jquery is still the most performant (mainly becasue it uses innerHTML)