jQuery Tips and Tricks - javascript

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
Syntax
Shorthand for the ready-event by roosteronacid
Line breaks and chainability by roosteronacid
Nesting filters by Nathan Long
Cache a collection and execute commands on the same line by roosteronacid
Contains selector by roosteronacid
Defining properties at element creation by roosteronacid
Access jQuery functions as you would an array by roosteronacid
The noConflict function - Freeing up the $ variable by Oli
Isolate the $ variable in noConflict mode by nickf
No-conflict mode by roosteronacid
Data Storage
The data function - bind data to elements by TenebrousX
HTML5 data attributes support, on steroids! by roosteronacid
The jQuery metadata plug-in by Filip Dupanović
Optimization
Optimize performance of complex selectors by roosteronacid
The context parameter by lupefiasco
Save and reuse searches by Nathan Long
Creating an HTML Element and keeping a reference, Checking if an element exists, Writing your own selectors by Andreas Grech
Miscellaneous
Check the index of an element in a collection by redsquare
Live event handlers by TM
Replace anonymous functions with named functions by ken
Microsoft AJAX framework and jQuery bridge by Slace
jQuery tutorials by egyamado
Remove elements from a collection and preserve chainability by roosteronacid
Declare $this at the beginning of anonymous functions by Ben
FireBug lite, Hotbox plug-in, tell when an image has been loaded and Google CDN by Colour Blend
Judicious use of third-party jQuery scripts by harriyott
The each function by Jan Zich
Form Extensions plug-in by Chris S
Asynchronous each function by OneNerd
The jQuery template plug-in: implementing complex logic using render-functions by roosteronacid

Creating an HTML Element and keeping a reference
var newDiv = $("<div />");
newDiv.attr("id", "myNewDiv").appendTo("body");
/* Now whenever I want to append the new div I created,
I can just reference it from the "newDiv" variable */
Checking if an element exists
if ($("#someDiv").length)
{
// It exists...
}
Writing your own selectors
$.extend($.expr[":"], {
over100pixels: function (e)
{
return $(e).height() > 100;
}
});
$(".box:over100pixels").click(function ()
{
alert("The element you clicked is over 100 pixels height");
});

jQuery's data() method is useful and not well known. It allows you to bind data to DOM elements without modifying the DOM.

Nesting Filters
You can nest filters (as nickf showed here).
.filter(":not(:has(.selected))")

I'm really not a fan of the $(document).ready(fn) shortcut. Sure it cuts down on the code but it also cuts way down on the readability of the code. When you see $(document).ready(...), you know what you're looking at. $(...) is used in far too many other ways to immediately make sense.
If you have multiple frameworks you can use jQuery.noConflict(); as you say, but you can also assign a different variable for it like this:
var $j = jQuery.noConflict();
$j("#myDiv").hide();
Very useful if you have several frameworks that can be boiled down to $x(...)-style calls.

Ooooh, let's not forget jQuery metadata! The data() function is great, but it has to be populated via jQuery calls.
Instead of breaking W3C compliance with custom element attributes such as:
<input
name="email"
validation="required"
validate="email"
minLength="7"
maxLength="30"/>
Use metadata instead:
<input
name="email"
class="validation {validate: email, minLength: 2, maxLength: 50}" />
<script>
jQuery('*[class=validation]').each(function () {
var metadata = $(this).metadata();
// etc.
});
</script>

Live Event Handlers
Set an event handler for any element that matches a selector, even if it gets added to the DOM after the initial page load:
$('button.someClass').live('click', someFunction);
This allows you to load content via ajax, or add them via javascript and have the event handlers get set up properly for those elements automatically.
Likewise, to stop the live event handling:
$('button.someClass').die('click', someFunction);
These live event handlers have a few limitations compared to regular events, but they work great for the majority of cases.
For more info see the jQuery Documentation.
UPDATE: live() and die() are deprecated in jQuery 1.7. See http://api.jquery.com/on/ and http://api.jquery.com/off/ for similar replacement functionality.
UPDATE2: live() has been long deprecated, even before jQuery 1.7. For versions jQuery 1.4.2+ before 1.7 use delegate() and undelegate(). The live() example ($('button.someClass').live('click', someFunction);) can be rewritten using delegate() like that: $(document).delegate('button.someClass', 'click', someFunction);.

Replace anonymous functions with named functions. This really supercedes the jQuery context, but it comes into play more it seems like when using jQuery, due to its reliance on callback functions. The problems I have with inline anonymous functions, are that they are harder to debug (much easier to look at a callstack with distinctly-named functions, instead 6 levels of "anonymous"), and also the fact that multiple anonymous functions within the same jQuery-chain can become unwieldy to read and/or maintain. Additionally, anonymous functions are typically not re-used; on the other hand, declaring named functions encourages me to write code that is more likely to be re-used.
An illustration; instead of:
$('div').toggle(
function(){
// do something
},
function(){
// do something else
}
);
I prefer:
function onState(){
// do something
}
function offState(){
// do something else
}
$('div').toggle( offState, onState );

Defining properties at element creation
In jQuery 1.4 you can use an object literal to define properties when you create an element:
var e = $("<a />", { href: "#", class: "a-class another-class", title: "..." });
... You can even add styles:
$("<a />", {
...
css: {
color: "#FF0000",
display: "block"
}
});
Here's a link to the documentation.

instead of using a different alias for the jQuery object (when using noConflict), I always write my jQuery code by wrapping it all in a closure. This can be done in the document.ready function:
var $ = someOtherFunction(); // from a different library
jQuery(function($) {
if ($ instanceOf jQuery) {
alert("$ is the jQuery object!");
}
});
alternatively you can do it like this:
(function($) {
$('...').etc() // whatever jQuery code you want
})(jQuery);
I find this to be the most portable. I've been working on a site which uses both Prototype AND jQuery simultaneously and these techniques have avoided all conflicts.

Check the Index
jQuery has .index but it is a pain to use, as you need the list of elements, and pass in the element you want the index of:
var index = e.g $('#ul>li').index( liDomObject );
The following is much easier:
If you want to know the index of an element within a set (e.g. list items) within a unordered list:
$("ul > li").click(function () {
var index = $(this).prevAll().length;
});

Shorthand for the ready-event
The explicit and verbose way:
$(document).ready(function ()
{
// ...
});
The shorthand:
$(function ()
{
// ...
});

On the core jQuery function, specify the context parameter in addition to the selector parameter. Specifying the context parameter allows jQuery to start from a deeper branch in the DOM, rather than from the DOM root. Given a large enough DOM, specifying the context parameter should translate to performance gains.
Example: Finds all inputs of type radio within the first form in the document.
$("input:radio", document.forms[0]);
Reference: http://docs.jquery.com/Core/jQuery#expressioncontext

Not really jQuery only but I made a nice little bridge for jQuery and MS AJAX:
Sys.UI.Control.prototype.j = function Sys$UI$Control$j(){
return $('#' + this.get_id());
}
It's really nice if you're doing lots of ASP.NET AJAX, since jQuery is supported by MS now having a nice bridge means it's really easy to do jQuery operations:
$get('#myControl').j().hide();
So the above example isn't great, but if you're writing ASP.NET AJAX server controls, makes it easy to have jQuery inside your client-side control implementation.

Optimize performance of complex selectors
Query a subset of the DOM when using complex selectors drastically improves performance:
var subset = $("");
$("input[value^='']", subset);

Speaking of Tips and Tricks and as well some tutorials. I found these series of tutorials (“jQuery for Absolute Beginners” Video Series) by Jeffery Way are VERY HELPFUL.
It targets those developers who are new to jQuery. He shows how to create many cool stuff with jQuery, like animation, Creating and Removing Elements and more...
I learned a lot from it. He shows how it's easy to use jQuery.
Now I love it and i can read and understand any jQuery script even if it's complex.
Here is one example I like "Resizing Text"
1- jQuery...
<script language="javascript" type="text/javascript">
$(function() {
$('a').click(function() {
var originalSize = $('p').css('font-size'); // get the font size
var number = parseFloat(originalSize, 10); // that method will chop off any integer from the specified variable "originalSize"
var unitOfMeasure = originalSize.slice(-2);// store the unit of measure, Pixle or Inch
$('p').css('font-size', number / 1.2 + unitOfMeasure);
if(this.id == 'larger'){$('p').css('font-size', number * 1.2 + unitOfMeasure);}// figure out which element is triggered
});
});
</script>
2- CSS Styling...
<style type="text/css" >
body{ margin-left:300px;text-align:center; width:700px; background-color:#666666;}
.box {width:500px; text-align:justify; padding:5px; font-family:verdana; font-size:11px; color:#0033FF; background-color:#FFFFCC;}
</style>
2- HTML...
<div class="box">
Larger |
Smaller
<p>
In today’s video tutorial, I’ll show you how to resize text every time an associated anchor tag is clicked. We’ll be examining the “slice”, “parseFloat”, and “CSS” Javascript/jQuery methods.
</p>
</div>
Highly recommend these tutorials...
http://blog.themeforest.net/screencasts/jquery-for-absolute-beginners-video-series/

Asynchronous each() function
If you have really complex documents where running the jquery each() function locks up the browser during the iteration, and/or Internet Explorer pops up the 'do you want to continue running this script' message, this solution will save the day.
jQuery.forEach = function (in_array, in_pause_ms, in_callback)
{
if (!in_array.length) return; // make sure array was sent
var i = 0; // starting index
bgEach(); // call the function
function bgEach()
{
if (in_callback.call(in_array[i], i, in_array[i]) !== false)
{
i++; // move to next item
if (i < in_array.length) setTimeout(bgEach, in_pause_ms);
}
}
return in_array; // returns array
};
jQuery.fn.forEach = function (in_callback, in_optional_pause_ms)
{
if (!in_optional_pause_ms) in_optional_pause_ms = 10; // default
return jQuery.forEach(this, in_optional_pause_ms, in_callback); // run it
};
The first way you can use it is just like each():
$('your_selector').forEach( function() {} );
An optional 2nd parameter lets you specify the speed/delay in between iterations which may be useful for animations (the following example will wait 1 second in between iterations):
$('your_selector').forEach( function() {}, 1000 );
Remember that since this works asynchronously, you can't rely on the iterations to be complete before the next line of code, for example:
$('your_selector').forEach( function() {}, 500 );
// next lines of code will run before above code is complete
I wrote this for an internal project, and while I am sure it can be improved, it worked for what we needed, so hope some of you find it useful. Thanks -

Syntactic shorthand-sugar-thing--Cache an object collection and execute commands on one line:
Instead of:
var jQueryCollection = $("");
jQueryCollection.command().command();
I do:
var jQueryCollection = $("").command().command();
A somewhat "real" use case could be something along these lines:
var cache = $("#container div.usehovereffect").mouseover(function ()
{
cache.removeClass("hover").filter(this).addClass("hover");
});

I like declare a $this variable at the beginning of anonymous functions, so I know I can reference a jQueried this.
Like so:
$('a').each(function() {
var $this = $(this);
// Other code
});

Save jQuery Objects in Variables for Reuse
Saving a jQuery object to a variable lets you reuse it without having to search back through the DOM to find it.
(As #Louis suggested, I now use $ to indicate that a variable holds a jQuery object.)
// Bad: searching the DOM multiple times for the same elements
$('div.foo').each...
$('div.foo').each...
// Better: saving that search for re-use
var $foos = $('div.foo');
$foos.each...
$foos.each...
As a more complex example, say you've got a list of foods in a store, and you want to show only the ones that match a user's criteria. You have a form with checkboxes, each one containing a criteria. The checkboxes have names like organic and lowfat, and the products have corresponding classes - .organic, etc.
var $allFoods, $matchingFoods;
$allFoods = $('div.food');
Now you can keep working with that jQuery object. Every time a checkbox is clicked (to check or uncheck), start from the master list of foods and filter down based on the checked boxes:
// Whenever a checkbox in the form is clicked (to check or uncheck)...
$someForm.find('input:checkbox').click(function(){
// Start out assuming all foods should be showing
// (in case a checkbox was just unchecked)
var $matchingFoods = $allFoods;
// Go through all the checked boxes and keep only the foods with
// a matching class
this.closest('form').find("input:checked").each(function() {
$matchingFoods = $matchingFoods.filter("." + $(this).attr("name"));
});
// Hide any foods that don't match the criteria
$allFoods.not($matchingFoods).hide();
});

It seems that most of the interesting and important tips have been already mentioned, so this one is just a little addition.
The little tip is the jQuery.each(object, callback) function. Everybody is probably using the jQuery.each(callback) function to iterate over the jQuery object itself because it is natural. The jQuery.each(object, callback) utility function iterates over objects and arrays. For a long time, I somehow did not see what it could be for apart from a different syntax (I don’t mind writing all fashioned loops), and I’m a bit ashamed that I realized its main strength only recently.
The thing is that since the body of the loop in jQuery.each(object, callback) is a function, you get a new scope every time in the loop which is especially convenient when you create closures in the loop.
In other words, a typical common mistake is to do something like:
var functions = [];
var someArray = [1, 2, 3];
for (var i = 0; i < someArray.length; i++) {
functions.push(function() { alert(someArray[i]) });
}
Now, when you invoke the functions in the functions array, you will get three times alert with the content undefined which is most likely not what you wanted. The problem is that there is just one variable i, and all three closures refer to it. When the loop finishes, the final value of i is 3, and someArrary[3] is undefined. You could work around it by calling another function which would create the closure for you. Or you use the jQuery utility which it will basically do it for you:
var functions = [];
var someArray = [1, 2, 3];
$.each(someArray, function(item) {
functions.push(function() { alert(item) });
});
Now, when you invoke the functions you get three alerts with the content 1, 2 and 3 as expected.
In general, it is nothing you could not do yourself, but it’s nice to have.

Access jQuery functions as you would an array
Add/remove a class based on a boolean...
function changeState(b)
{
$("selector")[b ? "addClass" : "removeClass"]("name of the class");
}
Is the shorter version of...
function changeState(b)
{
if (b)
{
$("selector").addClass("name of the class");
}
else
{
$("selector").removeClass("name of the class");
}
}
Not that many use-cases for this. Never the less; I think it's neat :)
Update
Just in case you are not the comment-reading-type, ThiefMaster points out that the toggleClass accepts a boolean value, which determines if a class should be added or removed. So as far as my example code above goes, this would be the best approach...
$('selector').toggleClass('name_of_the_class', true/false);

Update:
Just include this script on the site and you’ll get a Firebug console that pops up for debugging in any browser. Not quite as full featured but it’s still pretty helpful! Remember to remove it when you are done.
<script type='text/javascript' src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
Check out this link:
From CSS Tricks
Update:
I found something new; its the the JQuery Hotbox.
JQuery Hotbox
Google hosts several JavaScript libraries on Google Code. Loading it from there saves bandwidth and it loads quick cos it has already been cached.
<script src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
// Load jQuery
google.load("jquery", "1.2.6");
google.setOnLoadCallback(function() {
// Your code goes here.
});
</script>
Or
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>
You can also use this to tell when an image is fully loaded.
$('#myImage').attr('src', 'image.jpg').load(function() {
alert('Image Loaded');
});
The "console.info" of firebug, which you can use to dump messages and variables to the screen without having to use alert boxes. "console.time" allows you to easily set up a timer to wrap a bunch of code and see how long it takes.
console.time('create list');
for (i = 0; i < 1000; i++) {
var myList = $('.myList');
myList.append('This is list item ' + i);
}
console.timeEnd('create list');

Use filtering methods over pseudo selectors when possible so jQuery can use querySelectorAll (which is much faster than sizzle). Consider this selector:
$('.class:first')
The same selection can be made using:
$('.class').eq(0)
Which is must faster because the initial selection of '.class' is QSA compatible

Remove elements from a collection and preserve chainability
Consider the following:
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
<li>Five</li>
</ul>
$("li").filter(function()
{
var text = $(this).text();
// return true: keep current element in the collection
if (text === "One" || text === "Two") return true;
// return false: remove current element from the collection
return false;
}).each(function ()
{
// this will alert: "One" and "Two"
alert($(this).text());
});
The filter() function removes elements from the jQuery object. In this case: All li-elements not containing the text "One" or "Two" will be removed.

Changing the type of an input element
I ran into this issue when I was trying to change the type of an input element already attached to the DOM. You have to clone the existing element, insert it before the old element, and then delete the old element. Otherwise it doesn't work:
var oldButton = jQuery("#Submit");
var newButton = oldButton.clone();
newButton.attr("type", "button");
newButton.attr("id", "newSubmit");
newButton.insertBefore(oldButton);
oldButton.remove();
newButton.attr("id", "Submit");

Judicious use of third-party jQuery scripts, such as form field validation or url parsing. It's worth seeing what's about so you'll know when you next encounter a JavaScript requirement.

Line-breaks and chainability
When chaining multiple calls on collections...
$("a").hide().addClass().fadeIn().hide();
You can increase readability with linebreaks. Like this:
$("a")
.hide()
.addClass()
.fadeIn()
.hide();

Use .stop(true,true) when triggering an animation prevents it from repeating the animation. This is especially helpful for rollover animations.
$("#someElement").hover(function(){
$("div.desc", this).stop(true,true).fadeIn();
},function(){
$("div.desc", this).fadeOut();
});

Using self-executing anonymous functions in a method call such as .append() to iterate through something. I.E.:
$("<ul>").append((function ()
{
var data = ["0", "1", "2", "3", "4", "5", "6"],
output = $("<div>"),
x = -1,
y = data.length;
while (++x < y) output.append("<li>" + info[x] + "</li>");
return output.children();
}()));
I use this to iterate through things that would be large and uncomfortable to break out of my chaining to build.

HTML5 data attributes support, on steroids!
The data function has been mentioned before. With it, you are able to associate data with DOM elements.
Recently the jQuery team has added support for HTML5 custom data-* attributes. And as if that wasn't enough; they've force-fed the data function with steroids, which means that you are able to store complex objects in the form of JSON, directly in your markup.
The HTML:
<p data-xyz = '{"str": "hi there", "int": 2, "obj": { "arr": [1, 2, 3] } }' />
The JavaScript:
var data = $("p").data("xyz");
data.str // "hi there"
typeof data.str // "string"
data.int + 2 // 4
typeof data.int // "number"
data.obj.arr.join(" + ") + " = 6" // "1 + 2 + 3 = 6"
typeof data.obj.arr // "object" ... Gobbles! Errrghh!

Related

I converted jQuery to JavaScript but I have questions

I converted an old Wordpress Plugin of mine from jQuery to plain JavaScript using a cheat sheet. I was very surprised that it seems to work right out of the box on my first try.
(function ($) {
$(document).ready(function ($) {
$('.comment-list > li .comment-reply').each(function () {
var reply = this;
/* collect every comment which needs a reply link */
var allchildren = $(reply).parent().children('.children').children().find(".comment-content");
$.each(allchildren, function (index, value) {
$(reply).clone().appendTo(value);
});
});
});
})(jQuery);
Became this:
const replybtns = document.querySelectorAll(".comment-list > li .comment-reply");
for (var i = 0; i < replybtns.length; i++) {
var replybtn = replybtns[i];
var replybtncp = replybtn.cloneNode(true);
var cc = replybtn.parentElement.querySelectorAll('.children div.comment-content');
var lastcc = cc[Object.keys(cc)[Object.keys(cc).length - 1]];
lastcc.appendChild(replybtncp);
}
This copies all reply links of all level 1 nested comments and appends them to the last comment.
Is this code okay? Is it really that simple? I tested it with firefox and chrome, and it seems to work.
One major difference is that the jQuery code calls appendTo(value); potentially multiple times per reply (i.e. per outer-loop iteration), depending on whether there are multiple matches found for the .comment-content selector.
But the plain JS version does not have an inner loop and only calls appendChild once per outer-loop iteration.
Some other minor differences:
the jQuery code is running in a handler to the DOMContentLoaded event. (Note that its outer anonymous function is a useless wrapper, and the second one could be jQuery(function($) {...). The JS code doesn't have this feature.
The use of Object.keys(cc) in the plain JS code is unnecessary. Getting the last element from a node list can be done in an easier way. However, this is something the jQuery code is not doing (getting the last element).
The jQuery children method is not exactly reflected in the plain JS code, as a querySelectorAll('.children div.comment-content') can in theory find .children matches that are not at the level right under the node that this is called on.
The jQuery code does not require that the .comment-content matches are div elements.

Select tags that starts with "x-" in jQuery

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.

Efficiently replacing strings within an HTML block in Javascript

I am using Javascript(with Mootools) to dynamically build a large page using HTML "template" elements, copying the same template many times to populate the page. Within each template I use string keywords that need to be replaced to create the unique IDs. I'm having serious performance issues however in that it takes multiple seconds to perform all these replacements, especially in IE. The code looks like this:
var fieldTemplate = $$('.fieldTemplate')[0];
var fieldTr = fieldTemplate.clone(true, true);
fieldTr.removeClass('fieldTemplate');
replaceIdsHelper(fieldTr, ':FIELD_NODE_ID:', fieldNodeId);
parentTable.grab(fieldTr);
replaceIdsHelper() is the problem method according to IE9's profiler. I've tried two implementations of this method:
// Retrieve the entire HTML body of the element, replace the string and set the HTML back.
var html = rootElem.get('html').replace(new RegExp(replaceStr, 'g'), id);
rootElem.set('html', html);
and
// Load the child elements and replace just their IDs selectively
rootElem.getElements('*').each(function(elem) {
var elemId = elem.get('id');
if (elemId != null) elemId = elemId.replace(replaceStr, id);
elem.set('id', elemId)
});
However, both of these approaches are extremely slow given how many times this method gets called(about 200...). Everything else runs fine, it's only replacing these IDs which seems to be a major performance bottleneck. Does anyone know if there's a way to do this efficiently, or a reason it might be running so slow? The elements start hidden and aren't grabbed by the DOM until after they're created so there's no redrawing happening.
By the way, the reason I'm building the page this way is to keep the code clean, since we need to be able to create new elements dynamically after loading as well. Doing this from the server side would make things much more complicated.
I'm not 100% sure, but it sounds to me that the problem is with the indexing of the dom tree.
First of all, do you must use ids or can you manage with classes? since you say that the replacement of the id is the main issue.
Also, why do you clone part of the dom tree instead of just inserting a new html?
You can use the substitute method of String (when using MooTools), like so:
var template = '<div id="{ID}" class="{CLASSES}">{CONTENT}</div>';
template.substitute({ID: "id1", CLASSES: "c1 c2", CONTENT: "this is the content" });
you can read more about it here http://mootools.net/docs/core/Types/String#String:substitute
Then, just take that string and put it as html inside a container, let's say:
$("container_id").set("html", template);
I think that it might improve the efficiency since it does not clone and then index it again, but I can't be sure. give it a go and see what happens.
there are some things you can do to optimise it - and what #nizan tomer said is very good, the pseudo templating is a good pattern.
First of all.
var fieldTemplate = $$('.fieldTemplate')[0];
var fieldTr = fieldTemplate.clone(true, true);
you should do this as:
var templateHTML = somenode.getElement(".fieldTemplate").get("html"); // no need to clone it.
the template itself should/can be like suggested, eg:
<td id="{id}">{something}</td>
only read it once, no need to clone it for every item - instead, use the new Element constructor and just set the innerHTML - notice it lacks the <tr> </tr>.
if you have an object with data, eg:
var rows = [{
id: "row1",
something: "hello"
}, {
id: "row2",
something: "there"
}];
Array.each(function(obj, index) {
var newel = new Element("tr", {
html: templateHTML.substitute(obj)
});
// defer the inject so it's non-blocking of the UI thread:
newel.inject.delay(10, newel, parentTable);
// if you need to know when done, use a counter + index
// in a function and fire a ready.
});
alternatively, use document fragments:
Element.implement({
docFragment: function(){
return document.createDocumentFragment();
}
});
(function() {
var fragment = Element.docFragment();
Array.each(function(obj) {
fragment.appendChild(new Element("tr", {
html: templateHTML.substitute(obj)
}));
});
// inject all in one go, single dom access
parentTable.appendChild(fragment);
})();
I did a jsperf test on both of these methods:
http://jsperf.com/inject-vs-fragment-in-mootools
surprising win by chrome by a HUGE margin vs firefox and ie9. also surprising, in firefox individual injects are faster than fragments. perhaps the bottleneck is that it's TRs in a table, which has always been dodgy.
For templating: you can also look at using something like mustache or underscore.js templates.

Attaching an event to multiple elements at one go

Say I have the following :
var a = $("#a");
var b = $("#b");
//I want to do something as such as the following :
$(a,b).click(function () {/* */}); // <= does not work
//instead of attaching the handler to each one separately
Obviously the above does not work because in the $ function, the second argument is the context, not another element.
So how can I attach the event to both the elements at one go ?
[Update]
peirix posted an interesting snippet in which he combines elements with the & sign; But something I noticed this :
$(a & b).click(function () { /* */ }); // <= works (event is attached to both)
$(a & b).attr("disabled", true); // <= doesn't work (nothing happens)
From what you can see above, apparently, the combination with the & sign works only when attaching events...?
The jQuery add method is what you want:
Adds more elements, matched by the given expression, to the set of matched elements
var a = $("#a");
var b = $("#b");
var combined = a.add(b)
Don't forget either that jQuery selectors support the CSS comma syntax. If you need to combine two arbitrary collections, everyone else's suggestions are on the mark, but if it's as simple as doing something to elements with IDs a and b, use $('#a,#b').
This question has already been answered, but I think a simpler more streamlined way to accomplish the same end would be to rely on the similarities between jQuery's and CSS's selector model and just do:
$("#a, #b").click(function () {/* */});
I use this frequently, and have never seen it not work (I can't speak for jQuery versions before 1.3.2 though as I have not tested this there). Hopefully this helps someone someday.
UPDATE: I just reread the thread, and missed the comment you made about having the nodes in question already saved off to variables, but this approach will still work, with one minor tweek. you will want to do:
var a = $("#a");
var b = $("#b");
$(a.selector+", "+b.selector).click(function () {/* */});
One of the cool things that jquery does is that it adds a few jquery specific properties to the node that it returns (selector, which is the original selector used to grab that node is one of them). You may run into some issues with this if the selector you used already contained commas. Its also probably arguable if this is any easier then just using add, but its a fun example of how cool jquery can be :).
You could just put them in an array:
$.each([a, b], function()
{
this.click(function () { });
});
Why don't you use an array? This works on my side:
$([item1, item2]).on('click', function() {
// your logic
});
I just tried messing around with this, and found something very cool:
$(a & b).click(function() { /* WORKS! */ });
supersweet!
Edit: Now I feel really embarrassed for not testing this properly. What this did, was actually to put the click event on everything... Not sure why it does that, though...
You can also make up a class name and give each element that you want to work with that class. Then you can bind the event to all elements sharing that class.
<p><a class="fakeClass" href="#">Click Me!</a></p>
<p><a class="fakeClass" href="#">No, Click Me!</a></p>
<div class="fakeClass">Please, Click Me!</div>
<script type="text/javascript">
$(function () {
$(".fakeClass").on("click", function () {
alert("Clicked!");
});
})
</script>
try this: sweet and simple.
var handler = function() {
alert('hi!');
}
$.each([a,b], function() {
this.click(handler);
}
BTW, this method is not worth the trouble.
If you already know there are just two of these methods, then I guess the best bet would be
a.click(handler);
b.click(handler);
Cheers!
Example:
$("[name=ONE_FIELD_NAME], [name=ANOTHER_FIELD_NAME]").keypress(function(e){alert(e.which);});

jQuery document.createElement equivalent?

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)

Categories