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

Posted October 7, 2009 at 10:18 AM by Ben Nadel

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:

  • $( "..." ).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:

  • $( "..." ).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:

  • <!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.




Reader Comments

Oct 7, 2009 at 11:13 AM // reply »
26 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 »
11,246 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 »
17 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 »
11,246 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 »
3 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 »
17 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 »
3 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 A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 24, 2013 at 11:21 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, Ha ha, let's us never speak of justifying "##" notation again :P ... read »
May 24, 2013 at 11:18 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Ah, so it was indeed how I vaguely remembered it to be: A direct assignment value = users.id[ i ] causes value to retain the sticky datatype of the query column. Although unnecessary in ... read »
May 24, 2013 at 9:11 AM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Brandon, Hi, No, I haven't been able to do that. I have just kept it as it is. ... read »
May 23, 2013 at 9:52 PM
Preventing Links In Standalone iPhone Applications From Opening In Mobile Safari
@Muhmmadibn Did you figure out a solution to launching PDFs? I am running into the same issues myself. There is no way to close the PDF or go back once you launch it. Thanks in advance! ... read »
May 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools