Using Script Tags As Data Contains In AJAX-Powered jQuery
Posted June 8, 2009 at 10:19 AM
Last week, I blogged about how cool it was that the jQuery metadata plugin used Script tags to store application meta-data. I liked this for a number of reasons including the mime-typed nature of the script tags and their contextual embedding. After demonstrating the script tag meta-data use in a static way, I thought it would be good to demonstrate it in an AJAX-powered way. In this example, I am going to be pulling down HTML table rows with embedded meta-data script tags:
| | | | | |
| | | |||
| | | |
As you can see in the data, I start off with an HTML table that only has its THEAD defined. When the DOM is ready to be interacted with, I then use jQuery to pull down the table's TBODY. This TBODY contains not only the row data, it also contains Script tags that contain row meta-data. Because each Script tag contains data for a given row, I am returning a Script tag for each TR:
Launch code in new window » Download code as text file »
- <!--- Bulid the query to be used in the demo. --->
- <cfset qGirl = QueryNew( "" ) />
-
- <!--- Add the ID column. --->
- <cfset QueryAddColumn(
- qGirl,
- "id",
- "cf_sql_integer",
- ListToArray( "1,2,3,4,5" )
- ) />
-
- <!--- Add the name column. --->
- <cfset QueryAddColumn(
- qGirl,
- "name",
- "cf_sql_varchar",
- ListToArray( "Libby,Molly,Sarah,Kim,Kit" )
- ) />
-
-
- <!--- Return the rendered HTML. --->
- <cfoutput>
-
- <tbody>
- <cfloop query="qGirl">
-
- <!---
- We need to create a unique ID for the row so that
- the JSON meta data can be associated with it.
- --->
- <cfset strRowID = "row-#CreateUUID()#" />
-
- <!--- Send meta data. --->
- <script
- type="text/x-json"
- rel="#strRowID#"
- class="metadata">
- {
- id: #qGirl.id#,
- name: "#HtmlEditFormat( qGirl.name )#"
- }
- </script>
-
- <tr id="#strRowID#">
- <td>
- #qGirl.id#
- </td>
- <td>
- #qGirl.name#
- </td>
- <td>
- <a class="delete">Delete</a>
- </td>
- </tr>
-
- </cfloop>
- </tbody>
-
- </cfoutput>
While the Script tags are created contextually to the TR to which they refer, I have to give the TR a unique ID and pass that via the REL attribute of the Script tag. This is because the Script tags are moved around by the browser when the html is appended to the table. As you can see from the video, after our append() method, the Script tags are all added to the table itself and are no longer accessible in the context of the associated TR. The REL attribute allows us to gather the script tags from their new location and still associate their data with the original row.
The association of this meta-data is done by the jQuery code that handles the AJAX response:
Launch code in new window » Download code as text file »
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html>
- <head>
- <title>jQuery And Script Tags With AJAX-Table Data</title>
- <script type="text/javascript" src="jquery-1.3.2.js"></script>
- <script type="text/javascript">
-
- // When the DOM has loaded, gather the table data.
- $(
- function(){
- $.ajax(
- {
- method: "get",
- url: "./scripts_data.cfm",
- dataType: "html",
- success: populateTable
- }
- );
- }
- );
-
-
- // I take the AJAX response and populate the table with
- // initailized records.
- function populateTable( strHTML ){
- var jTable = $( "#table" );
-
- // Append raw HTML to the table. We can initialize the
- // html data after we append it.
- //
- // NOTE: After we append the HTML, the Script tags
- // will have been stripped out and placed at the
- // bottom of the table!
- jTable.append( strHTML );
-
- // Log table HTML for demo.
- console.log( jTable.html() );
-
- // Bind the meta data (remember, script tags became
- // children of the table itself).
- jTable.find( "> script.metadata" ).each(
- function( intI, objScript ){
- var jThis = $( this );
- var jRow = $( "#" + jThis.attr( "rel" ) );
-
- // Bind the meta data to the row.
- jRow.data(
- "metadata",
- eval( "(" + jThis.html() + ")" )
- );
- }
- );
-
- // Gather records.
- var jRows = jTable.find( "tbody > tr" );
-
- // Now that the meta data is bound to the record,
- // let's hook up the row action links.
- jRows.find( "a.delete" )
- .attr( "href", "javascript:void( 0 )" )
- .click(
- function( objEvent ){
- var jRow = $( this ).parents( "tr:first" );
-
- // This doesn't really do anything - just
- // for demonstration purposes. Showing
- // how we can grab meta data from the row.
- confirm(
- "Are you sure you want to delete " +
- jRow.data( "metadata" ).name +
- " from the table?"
- );
-
- // Prevent default event.
- return( false );
- }
- )
- ;
- }
-
- </script>
- </head>
- <body>
-
- <h1>
- jQuery And Script Tags With AJAX-Table Data
- </h1>
-
- <table id="table" cellspacing="1" border="1" cellpadding="5">
- <thead>
- <tr>
- <th>
- ID
- </th>
- <th>
- Name
- </th>
- <th>
- Actions
- </th>
- </tr>
- </thead>
-
- <!--- Table data will loaded via AJAX. --->
- </table>
-
- </body>
- </html>
As you can see, after the AJAX response HTML is appended to the table, we loop over the Script tags and associate the JSON meta-data with the target TR using jQuery's data() method. Once this is done, we can easily gather the action links in each row and perform actions based on the associated meta-data.
I was a bit irritated and disappointed that the Script tags were stripped out of the HTML when it was appended to the table. I feel that this hurts the usefulness of script-based data storage. I will keep doing some experimentation to see if I can find a way to stop that from happening. But, until then, this code was a nice demonstration of how I was thinking about using the Script tags as data containers in AJAX-powered applications.
Download Code Snippet ZIP File
Post Comment | Ask Ben | Permalink | Other Searches | Print Page
Newer Post
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Older Post
jQuery And Script Tags As Data Containers
Reader Comments
Interesting.
I've been playing with the idea of metadata Javascript objects to make DOM manipulation easier. I think I like this approach better than what I was doing, though.
@Matt,
I'm still playing around with it. I'm not thrilled with the way that the script tags get moved around. I find it somewhat shady :)
@Ben
It seems to me that if you're using the rel attribute and maybe storing a hashmap in the metadata, the position in the page souldnt matter as much.
Something I'm curious to play with.
@Matt,
Yeah, that seems to be the way to solve this. From my experimentation, it seems that the script tags are always stripped out and added after the top-most element in the AJAX data.
Hey Ben,
You can post Javascript along with your HTML if you're willing to do a little extra work on the server side. Something like this:
---- PAGE.CFM ---
<HTML>
<head>
<script src="script.cfm"></script>
<script>
function callback(content)
{
// do stuff with my content here...
// or call foo() from my included script
}
</script>
</head>
<body>
<cf_whatever>
</cf_whatever>
</body>
</HTML>
---- SCRIPT.CFM ---
<cfoutput>
// This file includes a regular javascript, and a bunch of HTML embedded in a callback function.
function foo(bar) {return bar++;}
callback("#JsStringFormat(myHtmlContentHere)#");
</cfoutput>
@Ben,
Yeah, you can definitely pass HTML and Javascript along. And, what's nice is that in jQuery, the DOM ready method:
$( function(){} );
... will fire immediately if inside that Javascript.




