Given the following code why am I getting different values for a and b? I would have thought they would return the same thing:
(function() {
var a = $('#foo');
var Test = function(){
console.log(a); //outputs 'jQuery()'
var b = $('#foo');
console.log(b); //outputs 'jQuery(select#foo)' which is what I want
};
})();
This question stems from me trying to stick frequently used selectors into vars. Originally I was doing it in each method (like I did with var b in the above example) but then I found I needed to use the selectors in multiple methods so I moved the assignment out to be available (or so I thought) to all of the methods in that anonymous function. As you can see, it does not work. Why is this?
EDIT: this code is loaded by a method that is triggered by a click. The id foo is present at page load and is not dynamically set or changed.
Make sure that the code isn't called until after your page finishes loading!
$(function() {
// your code
});
Also, of course, you'll want to be careful about caching things that might be changed on the page by other parts of your client-side application.
Just to improve on the previous answer - b is only evaluated when you call the Test function, probably once the page is loaded. Cache the selectors inside document ready:
$(document).ready(function(){
var a = $('#foo');
});
I only cache selectors when I'm using the same selector inside a block of code. I use the $variable naming convention for this:
var $divs = $('div');
You can also chain functions together to avoid having to cache the selector:
$('div').append('hello world').addclass('hello').show();
Related
I'm working on a site containing a confusing chain of asynchronous effects. Often, effects do/undo each other several times before stopping. I am having a very hard time following the spaghetti code.
Is it possible to set a callback to run any time a DOM element is manipulated so I can follow the chain of effects the code is applying to it?
Edit: I am currently adding dozens of console.logs everywhere and wanted a cleaner approach.
One approach is hooking into the core jQuery functions and log the information you want. Here's some very rough code on a few functions that i've hijacked i.e hide and animate.
var log_for_functions = 'hide animate'.split(' ');
$.each( log_for_functions , function(){
var function_name = this;
var original_function = $.fn[ original_function_name ]; // get a reference to old function name
$.fn[ function_name ] = function () {
var r = original_function.apply(this, arguments);
console.log( function_name + ' called on element ', this );
return r;
}
});
Now if you hide an element using jquery $('#test').hide() then you will get the following output.
hide called on element [context: #test, selector: "#test"]
You can change this to fit your needs and even hook into other functions.
Not without setInterval.
You could just have the code that applies an effect also note what changed.
You could do this with data attributes.
<div data-state="some state" ...
console.log(targetElement.getAttribute("data-state");
targetElement.setAttribute("data-state","changes");
MakeChanges(targetElement);
The following article introduces two techniques that might work in your case, Mutation Observers and Keyframes:
http://www.backalleycoder.com/2012/08/06/css-selector-listeners/
For each technique the article points to the related library.
I am using the following function closure in a jqgrid (a jquery grid) to retain changes in edits when paging in a variable called 'retainedChanges'- does this look ok; Im i breaking any good practices in javascript;
the code works alright just want to make sure I dont introduce features that can break in the future
(function($){
var retainedChanges;
retainedChanges = new Array();
$.retainChangesOnPaging = function(){
var changedCells = $('#grid').jqGrid('getChangedCells');
// loop over changedCells array, removing duplicates if you want to...
return retainedChanges.push(/* this is inside the loop; push current value to array*/);
....
}
$.getRetainedChanges = function(){
return retainedChanges;
}
})(jQuery);
This works fine, although you should probably accept jQuery as an argument:
(function($){
This way, even if the $ symbol is being used for something else outside of your closure, it won't effect your code inside the closure.
2 more things:
1) You should declare and assign you variable together, and use [] instead of new Array().
2) You're missing a $ symbol here: ('#grid').
For a full rundown, look at this:
(function($){
var retainedChanges = [];
$.retainChangesOnPaging = function(){
var changedCells = $('#grid').jqGrid('getChangedCells');
// loop over changedCells array, removing duplicates if you want to...
return retainedChanges.push(/* this is inside the loop; push current value to array*/);
....
}
$.getRetainedChanges = function(){
return retainedChanges;
}
})(jQuery);
You are passing jQuery into a function that has no arguments and never uses the jQuery object passed in. You may have meant:
(function($){
Other than that it looks fine.
There are several things you could improve:
1) You pass jQuery to the function, but do not use it (you use global object $, if it is defined). Modify your code to accept one parameter, named $:
(function($){
2) You can shorten retainedChanges declaration:
var retainedChanges = new Array();
3) If you are trying to write jQuery plugin, then follow the following tutorial: jQuery: Plugins/Authoring
If not, then maybe use different global object than jQuery?
I am just wondering what the pros/cons would be between these two styles of coding:
var foo;
$(document).ready( function() {
foo = $find(fooID);
});
function OnBarClicked()
{
foo.doStuff();
foo.doMoreStuff();
}
compared to
function OnBarClicked()
{
$find(fooID).doStuff();
$find(fooID).doMoreStuff();
}
I feel like there's probably a gotcha in the former, but I'm not aware of why there would be a gotcha. In addition, if there's any seek time for $find().. is it more efficient to find all variables guaranteed to be 'found' 2+ times at the start, and then use the one instance?
EDIT: $find description and usage
var radListBox1ID = "<%= RadListBox1.ClientID %>";
var radListBox = $find(radListBox1ID);
alert(radListBox.get_id()); //Alerts RadListBox1.ClientID
Assuming you're asking if querying the DOM once vs multiple (one per statement) with $()...
Yes, it is more efficient to use a single $() and store the result in a variable, rather than invoke jQuery at every statement if you are using the element multiple times within the same scope...
This is particularly useful in event handlers where you are referencing this as a jQuery object multiple times.
$('#element').click(function(e) {
var $clicked = $(this);
$clicked.doStuff();
$clicked.doMoreStuff();
});
First of all, you felt that there was a gotcha in the first example, and indeed, there is: You declare the foo variable in a local context that your onBarClicked function doesn't have access to. You'll get an undefined error if you try to use it. To fix that problem, declare foo in the global scope:
var foo;
$(document).ready(function () {
foo = $(fooID);
});
When it comes to your actual question, the short answer is: Yes. Running the search once and storing the result will be faster.
But if you're only searching for an element by its ID, then in all honesty it probably won't make much of a difference. The times when it really matters are when you have a complicated selector that involves attribute selectors or pseudo-elements or descendant combinators or stuff. You'd definitely want to save that result instead of running it again and again and again.
The first one doesn't work as your would expect since foo won't be defined in OnBarClicked. foo gets set in the callback function once the document is ready.
I recommend this aproach:
$( function () {
// get all the references (to the DOM elements) ASAP
var header = $( '#header' )[0],
nav = $( '#navigation' )[0],
toolbar = $( '#toolbar' )[0];
// etc.
// now whenever you need to work with a referenced DOM element
// just wrap it inside a jQuery object
$( nav ).click( function () { ... });
});
I can imagine the correct answer to this based on theory, but I'm just looking for some confirmation. I'm wondering what the most efficient way to re-use a jQuery-selected element is. For example:
$('#my_div').css('background','red');
//some other code
$('#my_div').attr('name','Red Div');
vs.
myDiv = $('#my_div');
myDiv.css('background','red');
//some other code
myDiv.attr('name','Red Div');
I assume the second example is more efficient because the element #my_div doesn't have to get found more than once. Is that correct?
Similarly, is it more efficient to first save $(this) in a varaible, such as 'obj', and then reuse 'obj' rather than using $(this) over and over? In this case, jQuery isn't being forced to find an element over and over again, but it IS being forced to convert this to a jQuery object [$(this)]. So as a general rule of thumb, should a jQuery object ALWAYS be stored in a variable if it will be used more than once?
You should write your code such that you limit the number of DOM traversals.
When you write something like this:
$('#my_div').css('background','red');
//some other code
$('#my_div').attr('name','Red Div');
You are finding #my_div twice, which is inefficient.
You can improve this either by assigning the result of a selector (i.e. var x = $('.something')) and manipulate the variable x, or you can chain your method calls like this:
$('#my_div').css('background','red').attr('name','Red Div');
You'll see the above code used a lot, because you're finding the element once. The css() method will apply a CSS style and return the actual result of $('#my_div'), so you can invoke another method, in this case attr().
My preferred way of handling the re-use of selectors is to store them as a variable, and wrap my stuff in a closure.
if you're using jQuery selector (like $('#element')), then yes, you should always store your results.
if you're using object and wrapping it in jQuery (like $(this)), it's not necessary, because jQuery doesn't need to search for that element again.
One thing that I find is generally overlooked is just how powerful jQuery chains are. It may not be so noticeable, but since jQuery caches your wrapped elements within a chain, you can modify elements, go into a more specific subset, modify, then go back up into a a general superset without much overhead.
I expect something like (pardon the example)
$('#myDiv')
.addClass('processing')
.find('#myInput')
.hide('slow')
.end()
.removeClass('processing')
;
to be better performance-wise than even
var $myDiv = $('#myDiv').addClass('processing');
var $myInput = $('#myDiv #myInput').hide('slow');
$myDiv.removeClass('processing');
This also holds for applying the jQuery function to elements returned in an event handler. Try to avoid applying $(...) too many times, because this is slow. Instead create a variable that contains the result of $(...). Good practice is to start the variable with a $, which gives a hint about the jQuery object inside the variable.
$('a').click(function(){
var $this = $(this);
$this.addClass("clicked");
$this.attr("clicked", true);
});
On mootools I'm used to declare once and reuse often. An FX example would go like this:
myEffect1 = new Fx.Slide($('myElement1'));
How should I go on jQuery? Meaning, the docs make it straightfoward to use:
$('myElement1').click(function(e){
this.slideToggle();
});
But if I want to call this effect somewhere else on my code will I have to re-declare it? And isn't this approach more resource hungry than the one above? How would this be properly done on jQuery?
Just manually cache the result set in a variable before calling the function, then reuse the function as needed:
var $el_one = $("#path .to > .selection"), // Stores jQuery object
$el_two = $("#path .to > .second"); // Stores jQuery object
var effect = function(){
$el_one.fadeIn();
$el_two.fadeOut();
}
Now you can call effect any time without reselecting the items. They instead use the cached jQuery selection to animate correctly.
If you need more clarity, let me know.
var slideToggleEffect = function(e){
this.slideToggle();
};
$('myElement1').click(slideToggleEffect);
$('myElement2').click(slideToggleEffect);
...
I'd go with a plugin in this case. For example here's a plugin that I use often - a very simple slide and fade toggle effect.
$.fn.slideFadeToggle = function(easing, callback) {
return this.animate({opacity: 'toggle', height: 'toggle'}, "fast", easing, callback);
};
Now you can call slideFadeToggle on any selector like this:
$("#somedom").slideFadeToggle();
Since every command acts on a jQuery object (the object returned by calling $() on a selector), the example you've given is the nearest comparison to what you're used to in MooTools, as far as I can see.
Is it more resource hungry? Well, that's a complex question to answer as instantiating objects is only one piece of client side code. Some framework methods for performing certain operations are better in some situations and worse in others.