Passing A Function To jQuery's Attr() Method For Implicit Iteration

Posted October 7, 2009 at 10:18 AM

Tags: Javascript / DHTML

In the past few weeks, I've outlined a number of really cool tips and tricks that I picked up from Cody Lindley's jQuery Enlightenment book; to cap it off, I wanted to cover just one more: passing a function as the second argument to the jQuery collection Attr() method. Typically, when we want to set the attribute of a given element using jQuery, we can pass the attribute name and value to the attr() method:

 Launch code in new window » Download code as text file »

  • $( "..." ).attr( "rel", "myRel" );

This call would apply the value, "MyRel," to the "rel" attribute of each element contained within the given jQuery collection. Most of this time, this is exactly what we want to do; however, sometimes, we want each element contained within the collection to have a computed attribute value. To accomplish this, we could use the each() method for implicit iteration, executing the attr() method on each item individually:

 Launch code in new window » Download code as text file »

  • $( "..." ).each(
  • function( index ){
  • $( this ).attr( "rel", ("MyRel" + index" ) );
  • }
  • );

This works fine; but, as it turns out, we can actually shorten it up a bit but passing a function as the second argument directly to the Attr() method. In the following demo, I am going to collect all the P tags and then define their IDs based on their position within the given collection:

 Launch code in new window » Download code as text file »

  • <!DOCTYPE HTML>
  • <html>
  • <head>
  • <title>jQuery Attr() Method And Function Argument</title>
  • <style type="text/css">
  •  
  • #p1 {
  • background-color: #FFEEEE ;
  • }
  •  
  • #p2 {
  • background-color: #EEFFEE ;
  • }
  •  
  • #p3 {
  • background-color: #EEEEFF ;
  • }
  •  
  • </style>
  • <script type="text/javascript" src="jquery-1.3.2.js"></script>
  • <script type="text/javascript">
  •  
  • // When the DOM is ready, intialize it.
  • $(function(){
  •  
  • // Set the ID of each P tag.
  • $( "p" ).attr(
  • "id",
  • function( index ){
  •  
  • // Return the value that we want to store into
  • // the ID attribute.
  • return( "p" + (index + 1) );
  •  
  • }
  • );
  •  
  • });
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • jQuery Attr() Method And Function Argument
  • </h1>
  •  
  • <p>
  • Paragraph One
  • </p>
  •  
  • <p>
  • Paragraph Two
  • </p>
  •  
  • <p>
  • Paragraph Three
  • </p>
  •  
  • </body>
  • </html>

As you can see, the function we pass to the Attr() method receives the index of the given element within the collection and then returns the value to be set into the attribute. When we run this, we get the following display:

 
 
 
 
 
 
Passing A Function To jQuery's Attr() Method For Implicit Iteration Of Elements. 
 
 
 

As you can see, each paragraph within the jQuery collection is given a different ID which, in turn, gives it a unique background color. This is a rather minor feature, but again, one of the many awesome efficiencies that jQuery provides in its tiny API.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Print Page




Learning ColdFusion 9 - ColdFusion 9 tutorials, samples, examples, demos

Reader Comments

Oct 7, 2009 at 11:13 AM // reply »
11 Comments

Interesting. Does the book say if this particular method is faster/more efficient than using an each() loop?


Oct 7, 2009 at 11:17 AM // reply »
6,516 Comments

@Brian,

I would assume that its slightly less efficient to do it this way since it's probably another layer of abstraction above the each() method itself; but, that's just a guess.


Oct 7, 2009 at 11:47 AM // reply »
10 Comments

I'm sure it wouldn't make much of a difference unless you were doing it thousands of time. And if you are, I bet the FireBug profiler would give you some good stats on which one was faster.


Oct 7, 2009 at 11:49 AM // reply »
6,516 Comments

@Brad,

Agreed. As long as we are using an abstraction layer, we might as well go with easy over slightly more efficient.

That said, however, there are definitely bulk-processing activities where that is probably not the case.


Oct 7, 2009 at 12:17 PM // reply »
2 Comments

I'm looking at the jQuery source, trying to reckon what implements this .attr(,function(){}) behaviour.

I don't see it. What am I missing?

My interest here is, looking at the jQuery source, what other native jQuery methods behave likewise? Because this is way cool.

For example, .html(function(){}) doesn't appear to work. That's OK, .html() is documented as-such, but how hard could it be to make that work?

Any insight on this? I don't see what actually executes the passed function(){} in the attr implementation.

Call it code blindness :-)


Oct 7, 2009 at 12:35 PM // reply »
10 Comments

@Steven: Around line 1855 in my v1.3.3pre of jQuery are the following bits:

jQuery.fn.extend({
attr: function( name, value ) {

This is what code runs when you call the attr() method of a jQuery object. You will see the first line is this:

var elem, options, isFunction = jQuery.isFunction(value);

This tests the value to see if it is a function or not (using another built-in jQuery method.
Down a few lines is the following statement:

if ( isFunction )
value = value.call(elem,i);

That should be what does it. Call is a built-in method to all JavaScript functions that lets you specify it's this scope and the parameters.

~Brad


Oct 7, 2009 at 12:41 PM // reply »
2 Comments

@Steven:
In jQuery.attr you can find a call to jQuery.prop
with options[name] (that your passed function) as second parameter.

In jQuery.prop you can read :
if ( jQuery.isFunction( value ) ) // <- value is the second param
value = value.call( elem, i );//here is the call to your passed function


Oct 7, 2009 at 12:43 PM // reply »
2 Comments

Too slow...
By the way, I was talking about jQuery 1.3.2.


Oct 7, 2009 at 1:18 PM // reply »
2 Comments

Thanks lads! That clarifies it. I got thrown by the proximate code-comment that implies the call is about resolving style values.

The interesting thing is, jQuery.prop() is called nowhere else in version 1.3.2. So apparently .attr() is the only method that's wired in this particular way.

I would have thought this function-for-value metaphor would be far more ubiquitous.


Post Comment  |  Ask Ben

Recent Blog Comments
Nov 21, 2009 at 11:03 AM
Groovy Operator Overloading Does Not Work In The ColdFusion Context
Hi Ben, Thanks for this informative post. Now I am reading ur old posts too ... read »
Nov 21, 2009 at 10:56 AM
HostMySite.com Has The Best ColdFusion Hosting
@Mehul, Yes very nice people, however several downtimes per day which was not acceptable. Hence we had to move out. I am glad you are having good luck with them so far. ... read »
Nov 20, 2009 at 11:32 PM
Five Months Without Hungarian Notation And I'm Loving It
I've used headless camel case for years for not only ColdFusion variables, but also SQL tables and fields... pretty much everything involving code. I also subscribe to the "don't abbreviate and clea ... read »
Nov 20, 2009 at 11:00 PM
Five Months Without Hungarian Notation And I'm Loving It
@Marcel, Yeah, I always err on the side of longer but more readable variable names. As for the camel casing of CF methods and the headless camel casing of custom items, I get around this by always ... read »
Nov 20, 2009 at 10:56 PM
Five Months Without Hungarian Notation And I'm Loving It
I use the following and love it: my.namespace.MyComponents.functionMethodsOrUDF() CONSTANT_VALUES_OR_PROPERTIES One thing I always try is to CamelCaseBuiltInColdFusionFunctions() so others can tell ... read »
Nov 20, 2009 at 5:38 PM
Learning ColdFusion 8: CFImage Part I - Reading And Writing Images
Hi Ben, Great article. I've been looking around to see if ColdFusion image engine can programatically create the following "wrap around" effect: http://www.creativepro.com/article/photoshop-s-she ... read »
Nov 20, 2009 at 5:35 PM
Maintaining ColdFusion Sessions Across SMS Text Message Requests Without Cookies
@Dave: I talked to Gert he suggested: <cfhttp method="get" url="http://{some cf website}" result="stuff" addtoken="yes" /> Note the addition of cfhttp attribute addtoken. That should persist y ... read »