views:

277

answers:

7

Hi everyone,

I recently learned (here on stackoverflow : ) ) that when using jquery every time I write

$("...")

a DOM search is performed to locate matching elements. My question is very simple: how do I efficiently perform a series of actions (using the nice methods of jquery objects) on a DOM element I have located with jquery? Currently, I was doing (eg):

var previousHtml = $("#myDiv").html();
$("#myDiv").addClass("tangoClass");
$("#myDiv").html("bla bla bla");
//...

Basically, I was always referring to the element by writing $("#myDiv"). How can I repeatedly manipulate a DOM element (using jquery functions, rather than vanilla Javascript) in an efficient way? Does the following avoid the costly DOM searches?

var myDiv = $("#myDiv");
var previousHtml = myDiv.html();
myDiv.addClass("tangoClass");
myDiv.html("bla bla bla");

Or should I instead try chaining the jquery calls as much as possible, eg:

var previousHtml = $("#myDiv").addClass("tangoClass").html(); //saves me 1 $("#myDiv") call
$("#myDiv").html("bla bla bla");

Thank you for any insight. : )

lara

A: 

Yes I would recommend to use chaining, because the jQuery methods usually return the element you modified, so it doesn't need to be looked up in the DOM again. And I find it more readable, too (you know which operations belong to which element).

Daff
+1  A: 

Every time you use a jQuery function, it returns the full jQuery object from the initial query. This lets you chain actions together, so the actual query only happens the first time.

From your examples, it doesn't look like you ever use previousHtml, so you don't need to grab it at all. I think you can just do this:

$("#myDiv").html('bla bla bla').addClass('tangoClass');
lo_fye
lo_flye, thank you! Getting previousHtml was just meant as an additional operation on the jquery object. Sometimes it is not possible to chain all operations, since some jquery functions don't return the jquery object (eg, .attr()). In those cases, storing the $() object in a variable and then performing actions on that variable is equivalent to chaining in terms of the lookups it triggers, right?
laramichaels
jvilalta addressed this below, thank you any way!
laramichaels
A: 

the two are the same.

var myDiv = $("#myDiv"); // $("#myDiv") runs document.getElementById,
                         // wraps the DOMElement, returns the wrapper.
myDiv.addClass("tangoClass"); // obviously reuses the object
myDiv.html("bla bla bla"); // ditto

chaining is exactly the same because jQuery methods return this, the object that they're attached to:

myDiv
    .AddClass("tangoClass")
    .html("bla bla bla")
;

you can test this with (myDiv === myDiv.html("bla bla bla"))

to answer your question "which should I use": DRY (Don't Repeat Yourself) would suggest chaining. just don't forget readability (don't lump many method calls into a single line; my recipe for readability is above)

just somebody
+1  A: 

It depends on which functions you are calling on that element, since not all functions will return the DOM element. However if all the functions you have to call will always return the DOM element, then it might certainly make your code more readable.

TskTsk
thank you, jvilalta! That was exactly my concern in the comment I posted under lo_flye's response. In those cases, I will just store the object returned by $("...") in a var.
laramichaels
Strictly speaking, jQuery functions never return DOM elements - they return a jQuery object that may contain an array of one or more DOM elements.
Jeff Sternal
A: 

Just because no one mentioned it, using your first method will also work and save the DOM search.

However, chaining, as the others said, would be the more "proper" way of using the same element and applying different actions to it.

Good luck!

Ken
+4  A: 

No one has linked jQuery Performance Rules yet, so I'll chime in, since it's a great article and a must-read for new jQuery developers!

As you'll see it confirms your suspicions: caching your jQuery objects by storing them in variables is just as effective as chaining.

Jeff Sternal
terrific resource, many thanks!
laramichaels
+1  A: 

I also agree that chaining is the best method to use, but something else no one has address here is using .andSelf()(1) and .end()(2) while chaining.

The following adds the "border" class to both the div and the p contained within.

$("div").find("p").andSelf().addClass("border");

Using .end() "resets" the selector

$("div")
  .find("p").addClass("myParagraph").end()
  .find("span").addClass("mySpan");
fudgey