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
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 22, 2013 at 5:35 PM
Script Tags, jQuery, And Html(), Text() And Contents()
This is still an issue 2 years later. jQuery is supposed to remediate these cross browser issues, no? I have been unable to find any statement from the jQuery team calling this behavior "by de ... read »
May 22, 2013 at 12:44 PM
Ask Ben: Query Loop Inside CFScript Tags
In cf10, if you call a function that has: local.result = {}; local.result.msg = ""; local.svc = new query(); local.svc.setSQL("SELECT * FROM..."); local.obj = local.svc.exe ... read »
May 22, 2013 at 12:29 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben: What version of Java are you using? Also, did you test users.id to see what Java reports as the data type? I wonder if it's not a Java primitive data type, but getting returned as something ... read »
May 22, 2013 at 11:47 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dana, Awesome - so it looks like this bug was fixed in ColdFusion 10. Thanks so much for double-checking that. ... read »
May 22, 2013 at 11:37 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
When I c&p and run on cf10, I get: Selected User IDs: 1,4 User 1 selected: YES - YES User 2 selected: NO - NO User 3 selected: NO - NO User 4 selected: YES - YES User 5 selected: NO - ... read »
May 22, 2013 at 11:27 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Tom, Good thought, but no dice. Both of these still exhibit the same behavior: users.id[ users.currentRow ] users[ "id" ][ users.currentRow ] It's just something whacky happening with ... read »
May 22, 2013 at 11:07 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
Could your problem be that "users.id" is actually an ARRAY, not a single value? Perhaps try it again with "users.id[1]" (I only have CF8 here at work). ... read »
May 22, 2013 at 7:52 AM
Nested Views, Routing, And Deep Linking With AngularJS
Hi, Just a quick thank you. As it happens, for my own purposes, the pending ui-router work being done in native angular is likely the one I'll adopt, but your exploration, code and documentation of ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools