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 »
20 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 »
10,640 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 »
16 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 »
10,640 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 »
16 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
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »
Feb 9, 2012 at 10:29 PM
Learning ColdFusion 9: Application-Specific Data Sources
@Ben, No offence, but if people were really wanting advanced features they would be using a platform like ASP.NET MVC. CFML is so structurally compromised as a tag-based scripting language that ... read »
Feb 9, 2012 at 10:03 PM
Subversion - Cleanup Failed To Process The Following Paths
@Leviaguirre, do you still have problems with this? ... read »