Using jQuery's $.map() Method To Convert Data Into Detached DOM Node Buffers

Posted November 1, 2011 at 10:13 AM by Ben Nadel

Tags: Javascript / DHTML

A couple of weeks ago, I blogged about the appendEach() jQuery plugin that allows you to append an array of jQuery objects to the rendered DOM tree. This plugin was created so that detached DOM (Document Object Model) nodes could be created and configured, en masse, without incurring the performance cost of visual rendering. At the heart of the plugin was a the $.map() method which translated the array of jQuery objects into an array of DOM nodes. While I like the plugin, I have found that in practice, it can be useful to just use the $.map() method directly to convert raw data into a detached DOM node buffer.

The jQuery $.map() method is pretty awesome. You give it an iterable object and a callback and it will give you an array:

  • var array = $.map( iterableObject, callback );

The returned array is the aggregate of all the values returned by the given callback. As I've talked about before, if you return an array from the callback, the $.map() method will merge the returned array into the aggregate array it is constructing. This allows the callback to return both single values as well as multi-value collections.

To demonstrate the power of this method, I'm going to use the jQuery $.map() method to convert raw data (such as the kind that might be returned from a remote AJAX call) into a detached DOM node buffer. This buffer will then be attached to the rendered page using the append() method.

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Using jQuery $.map() To Create DOM Buffers</title>
  • </head>
  • <body>
  •  
  • <h1>
  • Using jQuery $.map() To Create DOM Buffers
  • </h1>
  •  
  • <ul class="friends">
  • <!-- To be populated dynamically. -->
  • </ul>
  •  
  •  
  • <!-- BEGIN: Template. -->
  • <script type="text/x-template" class="friendTemplate">
  •  
  • <li class="friend">
  • <span class="name">[NAME]</span>
  • <span class="age">
  • (<span class="value">[AGE]</span>)
  • </span>
  • </li>
  •  
  • </script>
  • <!-- END: Template. -->
  •  
  •  
  • <script type="text/javascript" src="./jquery-1.7rc1.js"></script>
  • <script type="text/javascript">
  •  
  •  
  • // Get a reference to some DOM elements.
  • var friends = $( "ul.friends" );
  • var friendTemplate = $( $( "script.friendTemplate" ).html() );
  •  
  • // Define some data that we are going to use to populate our
  • // friend list.
  • var friendsData = [
  • {
  • id: 1,
  • name: "Tricia",
  • age: 35
  • },
  • {
  • id: 2,
  • name: "Joanna",
  • age: 39
  • },
  • {
  • id: 3,
  • name: "Sarah",
  • age: 30
  • },
  • {
  • id: 4,
  • name: "Kit",
  • age: 31
  • },
  • ];
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Now, we are going to use jQuery $.map() in order to
  • // create a detached buffer of DOM (Document Object Model)
  • // nodes that we'll append to the rendered page.
  • var buffer = $.map(
  • friendsData,
  • function( friendData, index ){
  •  
  • // Create a new instance of the friend template.
  • var friend = friendTemplate.clone();
  •  
  • // Populate the values.
  • friend
  • .attr( "data-id", friendData.id )
  • .find( "span.name" )
  • .text( friendData.name )
  • .end()
  • .find( "span.age span.value" )
  • .text( friendData.age )
  • .end()
  • ;
  •  
  • // Now, return the raw DOM node. Since we are using
  • // $.map(), this will result in an array of raw DOM
  • // nodes.
  • return( friend.get() );
  •  
  • }
  • );
  •  
  •  
  • // Now that we have an array of non-rendered, detached DOM
  • // elements, we can go ahead and append them to the rendered
  • // node tree.
  • friends.append( buffer );
  •  
  •  
  • </script>
  •  
  • </body>
  • </html>

As you can see, I am using the $.map() method to iterate over the friendsData collection. For each datum within the collection, I am then creating and populating an instance of the LI template. Rather than appending this detached DOM node to the page, however, I am returning the underlying, raw DOM node as my callback response:

  • return( friend.get() );

The .get() method returns the encapsulated array of DOM nodes. The $.map() then takes this array and merges is into the aggregate array that it is constructing. Once the $.map() method has finished executing, it leaves us with an array of raw DOM nodes. This array is then subsequently attached to the rendered page:


 
 
 

 
 Using $.map() to convert data into detached DOM node buffers. 
 
 
 

Rendering and re-painting DOM nodes is a relatively expensive process. As such, I like to do as much configuration pre-rendering as possible. This usually means the construction of detached jQuery collections that can be used to set attributes, append text values, and bind event handlers. By using jQuery's $.map() method, we can easily leverage all of the power provided by the jQuery API while still ending up with a collection of raw DOM nodes.




Reader Comments

Nov 1, 2011 at 2:37 PM // reply »
10,743 Comments

@All,

Just did some quick debugging to make sure that worrying about *detached* DOM node buffers was actually worth-while. And it is:

http://www.bennadel.com/blog/2281-jQuery-Appends-Multiple-Elements-Using-Efficient-Document-Fragments.htm

jQuery creates Document Fragments under the cover. That means it makes the insert of multiple nodes much more efficient.

Groooovy!


Nov 1, 2011 at 3:58 PM // reply »
1 Comments

This is pretty cool. I didn't know about this functionality. We use handlebarsjs to accomplish something similar. It's a pretty cool templating system. If you don't have a lot of changes to make with a lot of variables I think this method would be much snappier though.


Nov 2, 2011 at 6:03 PM // reply »
10,743 Comments

@Mike,

I don't know much about HandlebarsJS, but I've heard it's a pretty awesome templating system. Glad this looks interesting. I am sure each would have their place.


Apr 20, 2012 at 4:08 AM // reply »
1 Comments

Thank you for a great article and useful tips, guys!


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
May 21, 2012 at 1:58 AM
Updated: Converting A ColdFusion Query To CSV Using QueryToCSV()
Hi Ben, why do you need to have so many double quotes when adding the field and field name to the row data? ----------------------------------------- <cfset LOCAL.RowData[ LOCAL.ColumnIndex ] = ... read »
AXL
May 21, 2012 at 1:24 AM
URL Rewriting And ColdFusion's WriteToBrowser Image Functionality (CFFileServlet)
@Mounir, Open your lower case URL Rewrite rule and add the following condition. Condition input: {REQUEST_URI} Check if input string: Does Not Match the Pattern Pattern: ^/CFFileServlet/_cf_ca ... read »
May 20, 2012 at 4:28 AM
Understanding The Complex And Circular Relationships Between Objects In JavaScript
@Will Vaughn I tried your javascript example but got this error:- foo.print is not a function ... read »
May 19, 2012 at 5:37 AM
A Graphical Explanation Of Javascript Closures In A jQuery Context
Thanks for this article, but I fear you missed an important point. If variables in the outer context change, these changes affect the inner anonymous functions as well. That means: if you change the ... read »
May 18, 2012 at 3:39 PM
Parsing CSV Data With An Input Stream And A Finite State Machine
Can you use file upload button with this? and read live? or does the file have to already be on the server saved? ... read »
May 18, 2012 at 1:06 AM
VIRGO (Aug. 23-Sept. 22): Dead On The Money!
A friend of mine and I were arguing about astrology and she told me that he believes in astrology. She hasn't provided me with any evidence that the belief makes any sense to me. She she been telling ... read »
May 17, 2012 at 11:32 PM
Using ColdFusion to Handle 404 Errors (Page Not Found) On Development Server
Very easy the configuration. I read a lot pages and I can't find the solution. I open the administrator and change this Administrator/server settings/Error Handlers/Missing Template Handler and p ... read »
May 17, 2012 at 3:13 PM
LOCAL Variables Scope Conflicts With ColdFusion Query of Queries
I never cease to be amazed that almost EVERY random CF issue I come across lands me on your site. Thank you for documenting your findings for the world. ... read »