Using the Text Plugin With RequireJS To Load Remote HTML Templates

Posted October 28, 2011 at 10:57 AM by Ben Nadel

Tags: Javascript / DHTML

Earlier this week, I started looking into the RequireJS library as a way to manage JavaScript dependencies and modular application design. In addition to the core functionality of loading modules, RequireJS also has a plugin architecture that enables the loading of non-JavaScript data types. The "Text" plugin, for example, allows text files to be loaded-in as dependencies in the context of define() and require() method calls. Since a large part of our thick-client applications involve heavy DOM (Document Object Model) manipulation, I thought this would be a good feature to explore next.


 
 
 

 
  
 
 
 

Plugins, in RequireJS, are simply modules that adhere to a specific API. When you want to load a module using a plugin, you define the plugin as a prefix of the dependency. So for example, when using the Text plugin to load an HTML file, you might define the dependency as such:

  • text!template.htm

Notice that a "!" character is being used to separate the plugin prefix from the dependency suffix. In the above definition, it is not necessarily clear that the "text" plugin is actually a module itself; but, consider that the above line could be rewritten with this kind of format:

  • ./plugins/text!./templates/template.htm

In this format, it starts to become a bit more obvious that the Text plugin is a module that gets loaded by RequireJS as a type of implicit dependency.

To explore this feature, I wanted to take an array of data objects and merge them into the DOM using a remote template. In order to make use of the "Text" plugin, however, I had to download the Text.js file and put it in an accessible directory, relative to the RequireJS demo.

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Using The Text Plugin With RequireJS</title>
  •  
  • <script type="text/javascript" src="./require-jquery.js"></script>
  • <script type="text/javascript">
  •  
  •  
  • // Define the friends module. This is just a JSON object
  • // that we want to use as our test data. Since this is not
  • // being loaded in from a file, we have to give it an
  • // explicit name (such that it can be used as a dependency
  • // for other modules).
  • //
  • // NOTE: You need to supply an empty dependencies array in
  • // order to not confuse the define() method.
  • define(
  • "friends.data",
  • [ /** no dependencies. **/ ],
  • [
  • {
  • "id": 1,
  • "name": "Sarah",
  • "age": 35
  • },
  • {
  • "id": 2,
  • "name": "Tricia",
  • "age": 38
  • },
  • {
  • "id": 3,
  • "name": "Joanna",
  • "age": 29
  • },
  • {
  • "id": 4,
  • "name": "Libby",
  • "age": 37
  • }
  • ]
  • );
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // Now, let's require the data AND the template in order to
  • // render the page properly.
  • require(
  • [
  • "friends.data",
  • "text!friend-template.htm"
  • ],
  • function( friendsData, friendHtml ){
  •  
  • // Now that we've loaded the template and data, let's
  • // make sure we're waiting for the DOM-ready event.
  • // Since we loaded the jQuery/RequireJS library, we
  • // can use jQuery to get the DOM-ready.
  • $(function(){
  •  
  • // Get the friends list.
  • var friendsList = $( "ul.friends" );
  •  
  • // Get the template node (which we will use to
  • // create the friends.
  • var template = $( friendHtml );
  •  
  • // Map the array of friends' data into an array
  • // of template nodes to be added to the DOM.
  • var buffer = $.map(
  • friendsData,
  • function( friendData, index ){
  •  
  • // Close the template.
  • var friend = template.clone();
  •  
  • // Set the name.
  • friend.find( "span.name" ).text(
  • friendData.name
  • );
  •  
  • // Set the age.
  • friend.find( "span.age span.value" ).text(
  • friendData.age
  • );
  •  
  • // Return the raw node.
  • return( friend.get() );
  •  
  • }
  • );
  •  
  • // Insert the friend template DOM node buffer
  • // into the page.
  • friendsList.append( buffer );
  •  
  • });
  •  
  • }
  • );
  •  
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • Using The Text Plugin With RequireJS
  • </h1>
  •  
  • <h2>
  • Friends
  • </h2>
  •  
  • <ul class="friends">
  • <!-- To be populated dynamically. -->
  • </ul>
  •  
  • </body>
  • </html>

Notice that in this exploration, I am putting a define() function call right into the main file. While it is recommended that each module be placed in its own file, I thought I was seize this as an opportunity to explore explicitly named modules; since this define() usage, in this case, cannot map a file path to a module, we have to provide the module name - friends.data - as part of the define() invocation.

Once the friends data has been loaded, I use a require() call and the Text plugin to load in the HTML template. Here is the HTML file that is being loaded:

friend-template.htm (Our Remote HTML Template)

  • <!-- BEGIN: Friend Template. -->
  • <li class="friend">
  • <span class="name">NAME</span>
  • <span class="age">( Age: <span class="value">AGE</span> )</span>
  • </li>
  • <!-- END: Friend Template. -->

Once this dependency has been loaded, I can then merge the "friends.data" module with the template in order to update the DOM (Document Object Model). When we run the above code, we get a dynamically populated page:


 
 
 

 
 RequireJS can use the Text plugin to load remote HTML files. 
 
 
 

As you can see, the Text plugin automatically loaded the remote HTML template and then passed the string value through to the given asynchronous callback. We were then able to use jQuery (which was loaded as part of the "require-jquery.js" library version) in order to convert the HTML string into a usable DOM fragments.

So far, everything I've tried with the RequireJS library just seems to work. I feel somewhat silly for having put it off for so long. I had assumed that it would be difficult to use; but, it's exactly the opposite. I'm really liking it.




Reader Comments

Feb 4, 2012 at 6:05 PM // reply »
2 Comments

Nice video, helped a lot. Why do we define modules when the function of Require JS is just to load things, not to manage things?


Mar 12, 2012 at 1:24 PM // reply »
1 Comments

One question -- in your usage of jQuery to ensure the DOM is ready, there's no $(document).ready() wrapped around your function. Is the DOM's ready state already implied in some other way? I'm scratching my head over that part.

Love these RequireJS posts, by the way.


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 »