JavaScript/JQuery: use $(this) in a variable-name - javascript

I'm writing a jquery-plugin, that changes a css-value of certain elements on certain user-actions.
On other actions the css-value should be reseted to their initial value.
As I found no way to get the initial css-values back, I just created an array that stores all initial values in the beginning.
I did this with:
var initialCSSValue = new Array()
quite in the beginning of my plugin and later, in some kind of setup-loop where all my elements get accessed I used
initialCSSValue[$(this)] = parseInt($(this).css('<CSS-attribute>'));
This works very fine in Firefox.
However, I just found out, that IE (even v8) has problems with accessing the certain value again using
initialCSSValue[$(this)]
somewhere else in the code. I think this is due to the fact, that I use an object ($(this)) as a variable-name.
Is there a way arround this problem?
Thank you

Use $(this).data()
At first I was going to suggest using a combination of the ID and the attribute name, but every object might not have an ID. Instead, use the jQuery Data functions to attach the information directly to the element for easy, unique, access.
Do something like this (Where <CSS-attribute> is replaced with the css attribute name):
$(this).data('initial-<CSS-attribute>', parseInt( $(this).css('<CSS-attribute>') ) );
Then you can access it again like this:
$(this).data('initial-<CSS-attribute>');
Alternate way using data:
In your plugin, you could make a little helper function like this, if you wanted to avoid too much data usage:
var saveCSS = function (el, css_attribute ) {
var data = $(el).data('initial-css');
if(!data) data = {};
data[css_attribute] = $(el).css(css_attribute);
$(el).data('initial-css', data);
}
var readCSS = function (el, css_attribute) {
var data = $(el).data('initial-css');
if(data && data[css_attribute])
return data[css_attribute];
else
return "";
}

Indexing an array with a jQuery object seems fishy. I'd use the ID of the object to key the array.
initialCSSValue[$(this).attr("id")] = parseInt...

Oh please, don't do that... :)
Write some CSS and use the addClass and removeClass - it leaves the styles untouched afterwards.

if anybody wants to see the plugin in action, see it here:
http://www.sj-wien.at/leopoldstadt/zeug/marcel/slidlabel/jsproblem.html

Related

Deleting an element from JSON in javascript/jquery

I have a problem in deleting data from a JSON object in javascript. I'm creating this JSON dynamically and the removal shall also take place dynamically. Below is my JSON and the situation I'm in to.
{brands:[51,2046,53,67,64]}
Now, I have to remove 53 from this which I am calculating using some elements property, but I'm not able to remove the data and unable to find the solution for this situation. Please help me folks, thank you.
Try to use Array.prototyp.splice,
var data = { brands:[51,2046,53,67,64] };
data.brands.splice(2,1);
Since you want to remove an element from an array inside of a simple object. And splice will return an array of removed elements.
If you do not know the position of the element going to be removed, then use .indexOf() to find the index of the dynamic element,
var elementTobeRemoved = 53;
var data = { brands:[51,2046,53,67,64] };
var target = data.brands;
target.splice(target.indexOf(elementTobeRemoved),1);
You could write the same thing as a function like below,
function removeItem(arr,element){
return arr.splice(arr.indexOf(element),1);
}
var data = { brands:[51,2046,53,67,64] };
var removed = removeItem(data.brands,53);

Accessing a Dynamically Named array in jQuery/javascript

I wish to name an array according to the table row containing the button that was clicked.
I get the table row thus:
var rowNum = $(this).parent().parent().index();
Now, I wish to name the array and access it.
var arrayName = 'arrTR' + rowNum;
window[arrayName] = new Array();
window[arrayName]["First"] = "Bob";
window[arrayName]["Last"] = "Roberts";
window[arrayName]["email"] = "me#there.com";
//The array should be accessible as arrTR__
alert(arrTR1["Last"]);
The alert does not work, so I am doing something wrong.
How should I refactor the code to allow me to update and access the array?
jsFiddle
What you're doing with the dynamically named variables is essentially creating an array of those variables (one for each rowNum), but giving each of those array elements its own individual named variable.
There is a much better way to do this. Instead of generating a series of dynamically named variables, make a single array or an object. Then add an element or property for each of the dynamically named variables you were going to generate.
Your test code could look like this:
var arrTR = [];
var rowNum = 1;
arrTR[rowNum] = {
First: 'Bob',
Last: 'Roberts',
email: 'me#there.com'
};
alert( arrTR[1].Last );
Alternatively, you can do something with $.data as mentioned in Johan's answer. But if you do use plain JavaScript code, use a single array as described here instead of multiple dynamically named variables.
There are several reasons to do it this way. It's cleaner and easier to understand the code, it may be faster when there are large numbers of entries, and you don't have to pollute the global namespace at all. You can define the var arrTR = []; in any scope that's visible to the other code that uses it.
Arrays and objects are made for keeping track of lists of things, so use them.
There is nothing wrong with your code, and the only place it has error is the alert since it is not defined on the first click button
see this fiddle with a little update
if(rowNum === 1)
alert(arrTR1["Last"]);
else if(rowNum === 2)
alert(arrTR2["Last"]);
fiddle
How about something like this?
$('.getinfo').click(function() {
var result = $('table tr:gt(0)').map(function(k, v){
return {
firstName: $(v).find('.fname').val(),
lastName: $(v).find('.lname').val(),
email: $(v).find('.email').val(),
}
}).get();
//update to show how you use the jQuery cache:
//1. set the value (using the body tag in this example):
$('body').data({ result: result });
//2. fetch it somewhere else:
var res = $('body').data('result');
});
Not sure how you want to handle the first row. I skip in in this case. You can access each row by result[index].
As you might have noticed, this saves all rows for each click. If you want to use the clicked row only, use the this pointer.
http://jsfiddle.net/nwW4h/4/

How can I store a value (string) in a web page

I would like to store the value of something on my web page for later use by
some javascript functions. I thought of doing something like this where I have
a div with an id of CategoryID and then put the value in that as HTML.
<div id="CategoryID"></div>
$('#categories > li > a').click(function (e) {
e.preventDefault();
$('#CategoryID').html = $(this).attr('data-value')
refreshGrid('Reference');
});
Then later inside functions such as refreshGrid (and some other functions), I could get the value like this:
var categoryID = $('#CategoryID').val();
Does this seem like a good way to store a temporary variable? How about with
HTML5, is there some way to store values without having to put them inside a
div or something like that. All I need is to have a value that is stored in some
way on the page.
One more question. If I store the value is this the correct way to do it:
$('#CategoryID').html = $(this).attr('data-value')
Please use HiddenField for storing variable using jquery just like this:
var tempvalue= $(this).attr('data-value');
$('#my-hidden-field').val(tempvalue);
Hope this is helpful for you.
Use hidden fields on your web-page. For instance.
<INPUT TYPE=HIDDEN NAME="customerId" VALUE="1234567">
And then use .val in JQuery to work with these values.
I'm sometimes using hidden inputs for this purpose depending on the specific case.
<input type="hidden" name="CategoryID" id="CategoryID" />
Then retrieve it just like this:
var categoryID = $('#CategoryID').val();
I use inputs since i feel html which isn't markup for the page shouldn't be there.
Sometimes the easiest thing is to just output the variable from the server into script.
Example with ASP.NET:
<script type="text/javascript">
//<!--
var categoryID = <%= <output value from server goes here> %>;
//-->
</script>
You should try using the localStorage API introduced in HTML5 if you're keen on that otherwise storing it in hidden fields are the way to go.
var idForStorage = $('#CategoryID').val();
window.localStorage.setItem('keyToId', idForStorage);
and to fetch it from localStorage
var fetchedId = window.localStorage.getItem('keyToId');
Note: the localstorage only stores values as Strings, remember that! :)
Also, if you want to be older browser compliant, don't forget to check if localStorage exists and implement a different solution.
Something along the lines of
if(typeof(window.localStorage) !== 'undefined'){
//set item or do whatever
} else {
//implement other solution or throw an exception
}
Good luck!
Just a thought but have you considered storing the value in a javascript variable? If you are only using it in javascript why bother putting it in a hidden field or an element at all?
Just declare you variable in the global scope if your not using namespacing/modules but if you are you can store it in the scope of the module that uses it.
Only considerations with this approach is the variable will be reset on page refresh but if you arnt using the value on the server, just in script then that should be ok.
In general I'd only use a hidden input if the server needed to be able to read it.
EDIT
In reposone to the comments, if you are using your javascript sensibly which includes the use of namespaceing then this approach works with a certain amount of elegance over cluttering up your markup with "variable holders"
A very quick scaffold for namespacing.....
in a file called MyProject.Global.js
//This function is truly global
function namespace(namespaceString) {
var parts = namespaceString.split('.'),
parent = window,
currentPart = '';
for (var i = 0, length = parts.length; i < length; i++) {
currentPart = parts[i];
parent[currentPart] = parent[currentPart] || {};
parent = parent[currentPart];
}
return parent;
}
in a file called MyProject.MyPage.Ui.js
namespace('MyProject.MyPage');
MyProject.MyPage.Ui = function () {
var self = this;
self.settings = {};
function init(options) {
$.extend(self.settings, options);
//any init code goes here, eg bind elements
setValue();
};
};
//this is considered a "private" function
function setValue(){
$('#categories > li > a').click(function (e) {
e.preventDefault();
self.settings.myValue = $(this).attr('data-value');
refreshGrid('Reference');
});
}
function getValue(){
return self.settings.myValue;
}
//any function within this return are considered "public"
return {
init: init,
getValue: getValue
};
};
finally in your page...
$(document).ready(function () {
var ui = new MyProject.MyPage.Ui();
ui.init();
}
then at any point you can get hold of your value using...
MyProject.MyPage.getValue()
The function val() gets the value of an element. But only inputs have values, therefore you should use a hidden input to store the data:
<input id="CategoryId" type="hidden" />
But generelly you can access any attribute as described below. Just be aware that attr() is old and the new function name is prop() -> see Comment for correct explanation regarding attr() and prop()
One more question. If I store the value is this the correct way to do it:
The easier way to use Data- attributes with jQuery is to use the .data() method.
<body id="CategoryData" data-value1="someone" data-value2="sometwo">
....
alert( $("#CategoryData").data('value1') ); // popup with text: someone
alert( $("#CategoryData").data('value2') ); // popup with text: sometwo
Personally, I would rather store all the data associated with items in a wrapper Div or other elements and use jquery.data.
<table data-locationid="1">
<tr data-personid="1">
<td>Jon</td>
<td>Doe</td>
</tr>
<tr data-personid="2">
<td>Jane</td>
<td>Doe</td>
</tr>
</table>
HTML5 data-* Attributes
As of jQuery 1.4.3 HTML 5 data- attributes will be automatically pulled in to jQuery's data object. The treatment of attributes with embedded dashes was changed in jQuery 1.6 to conform to the W3C HTML5 specification.
For browser compatibility, its wiser to use hidden field as suggested by others. But for exploratory reasons, if you would like to use HTML5 it offers WebStorage. For more information please look at http://sixrevisions.com/html/introduction-web-storage/
Also, there is a framework called Lawnchair the offers solution for html5 mobile apps that need a lightweight, adaptive, simple and elegant persistence solution.
There are three ways to store the values as you wish:
Cookies: the good old way. It is supported everywhere but is more suited for values that need to be kept over different pages and it has other limits (such as size, number of entries, etc).
SessionStorage: not supported everywhere, but there are shims. It allows you to store a value that will last for a session only. Example:
sessionStorage.setItem('key', 'value')
sessionStorage.getItem('key', 'value')
This accepts strings only as keys and values. If you want to store objects, you can use JSON.stringify to store them, and retrieve them later with JSON.parse.
LocalStorage: the brother of sessionStorage, but it has no time limit. It allows you to store datas with the same API as sessionStorage and it's kept over time.
If you want to store the value in one part of your JavaScript for access from another part I'd just use a variable:
var categoryID = null; // set some kind of default
$('#categories > li > a').click(function (e) {
e.preventDefault();
categoryID = $(this).attr('data-value');
refreshGrid('Reference');
});
Then later when you need the value just access categoryID directly.
One more question. If I store the value is this the correct way to do it
If you did want to set the value as the content of your div element you'd use jQuery's .html() method or the non-jQuery .innerHTML property:
$('#CategoryID').html( $(this).attr('data-value') );
// or
$("#CategoryID")[0].innerHTML = $(this).attr('data-value');
But if you don't want to use a variable you'd be better off using a hidden input as mentioned in other answers rather than a div.

how can I assign object properties to dynamic elements based on the modulus operator

I have created a mini template that holds and <h2> & <h3>, I have created a loop that adds .inner everytime i%2 === 0, what i would like to do is split up the data being outputted to follow the same kind of rule so when i%2 === 0 add .inner and also split the object properties so each .inner should display 2 templated object properties. Can anyone advise on how this can be achieved? Also my templated items seem to return undefined?
Demo here http://jsbin.com/otirax/13/edit
Your code can be improved in many ways. The selector here:
$('.inner').append(temp);
should actually be $(".inner:last"), otherwise it affects all ".inner" objects created so far. Better yet, save a newly created div in a variable:
inner = $('<div class="inner"></div>').appendTo($('#ctn'));
and then simply use the var, thus saving an expensive selector operation:
inner.append(...);
Another improvement is to automate template rendering. Consider the following function: it populates arbitrary {{tags}} from an object:
function render(template, values) {
return template.replace(
/{{(\w+)}}/g,
function($0, $1) { return values[$1] });
}
Complete example: http://jsbin.com/iviziz/2/edit
. Let us know if you have questions.
Templated items seem to return undefined:
var temp = template.replace(/name/ig, data.name)
.replace(/age/ig, data.age);
Should be as below due to them being an array.
var temp = template.replace(/name/ig, data[i].name)
.replace(/age/ig, data[i].age);
I assume that thesonglessbird's reply was clear enough, but just to give a proper answer, instead of
var temp = template.replace(/\{\{name\}\}/ig, data.name)
.replace(/\{\{age\}\}/ig, data.age);
you would need to have
var temp = template.replace(/\{\{name\}\}/ig, data[i].name)
.replace(/\{\{age\}\}/ig, data[i].age);
you can see an example here http://jsbin.com/otirax/16/edit
Aside of that, schemantically a 'template' should not be placed inside script tags as it isn't a script.

jQuery Tips and Tricks

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!

Categories