jQuery And Script Tags As Data Containers

Posted June 5, 2009 at 9:59 AM

Tags: Javascript / DHTML

This morning, I was reading the latest post in Hal Helms' Learning jQuery series, when I saw that he was using the jQuery metadata() plugin. This metadata() plugin seems pretty cool, so I looked it up to see how it worked (I like to dig into cool things). Essentially, the plugin allows you to store application metadata through various conduits. Among the storage methodologies, it did something that I'd never seen before: it used HTML script tags to store non-Javascript information. Essentially, it was using the Script tag to store application data. Excited to try this, I threw together a quick demo:

 
 
 
 
 
 
 
 
 
 

NOTE: In the video, I am using text(), but I had to switch to html() for cross-browser compatibility.

As you can see from the video, the browser doesn't render the Script tags because they are script tags; but, at the same time, it doesn't error out because it's not trying to execute them as scripts either. This is quite brilliant and is blowing my mind a bit! The Type attribute of the Script tag is the mime type of the data contained within it. In my demonstration, I am using plain text, hence the "text/plain" type; but, you could change this to "application/json" as used by the metadata plugin for JSON data storage.

 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</title>
  • <script type="text/javascript" src="jquery-1.3.2.js"></script>
  • <script type="text/javascript">
  •  
  • // When DOM loads, initialize.
  • $(
  • function(){
  • // Gather script block in our target DIV.
  • var jScripts = $( "#scripts script" );
  •  
  • // Get a reference to our output list.
  • var jOutput = $( "#output" );
  •  
  • // Loop over each script to copy the data from
  • // the tag to the output list.
  • jScripts.each(
  • function( intI, objScript ){
  • var jThis = $( this );
  •  
  • // Append html of script tag to list.
  • jOutput.append(
  • "<li>" +
  • jThis.html() +
  • "</li>"
  • );
  • }
  • );
  •  
  • }
  • );
  •  
  • </script>
  • </head>
  • <body>
  •  
  • <h1>
  • jQuery And Script Tags
  • </h1>
  •  
  • <div id="scripts">
  •  
  • <script type="text/plain">
  • Plain text in script tag.
  • </script>
  •  
  • <script type="text/plain">
  • More plain text in script tag.
  • </script>
  •  
  • </div>
  •  
  • <ul id="output" />
  •  
  • </body>
  • </html>

The first time I tried to do this, I use the .text() method to gather the data in the Script tag. This worked in Firefox, but not in Internet Explore. I changed it to use the .html() method and this seemed to work fine in FireFox, IE, Safari, and Chrome. And, as you saw in the video, when we run this example, we get the following output:

jQuery And Script Tags

* Plain text in script tag.
* More plain text in script tag.

This technique is definitely going to revolutionize the way I pass DOM meta-data via server-side XHTML.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page





Reader Comments

Jun 5, 2009 at 11:04 AM // reply »
35 Comments

Maybe I'm being thick, but how does this help you more than a document/window scoped JSON literal?

<script type="text/javascript">
var metadata = [
"Plain text in script tag.",
"More plain text in script tag."
];
</script>


Jun 5, 2009 at 11:16 AM // reply »
6,371 Comments

@Rick,

The difference is that the script tags can be contextual to the HTML in which they are defined. For example, I could put a script tag inside each row of a data grid that contains information like ID that can be used to then make further row-related AJAX calls.

If you were just going to use window-scoped JSON, each tag might overwrite each other.


Jun 5, 2009 at 12:43 PM // reply »
6 Comments

Very Cool. I love jQuery.


James White
Jun 5, 2009 at 12:51 PM // reply »
1 Comments

Do you envision being able to use this with something like cfquery to load database information into jQuery, or is this strictly for text/XMl type stuff?

Thanks,

JW


Jun 5, 2009 at 12:57 PM // reply »
6,371 Comments

@James,

I picture it with being able to padding item-specific data along with HTML. So, for a query, if we were to generate a HTML table based on the data, I might pass a Script tag with *each* row with record-specific information.


Roland Collins
Jun 5, 2009 at 1:22 PM // reply »
31 Comments

@Ben

Wouldn't you just use input type="hidden" for that type of info? You get the same benefits of contextualization and DOM-based storage/parsing that you're looking for. It seems like the script solution is .... hacky.


Jun 5, 2009 at 1:26 PM // reply »
6,371 Comments

@Roland,

Yes, using a hidden input is a very nice option ... when you are inside of a FORM element. Also, I am not sure how I would feel about passing JSON data inside of a hidden input value. Could get messy and would be hard to write with all the quote / line-break escaping.


Roland Collins
Jun 5, 2009 at 1:29 PM // reply »
31 Comments

I can definitely see that being an issue.

I don't know - something about Hal's approach just makes me feel dirty :)


Jun 5, 2009 at 1:34 PM // reply »
6,371 Comments

@Roland,

Hal used the CSS-storage route of the metadata plugin. I agree with you that this feels a little kludgey. I also am not crazy about adding custom name-spaced HTML attributes, like:

<div app:id="3">

... which I believe the metadata plugin can also handle.

That's why I really like the SCRIPT tag version - it doesn't mess up or "override" any existing attribute usage. Plus, because the type attribute of the Script tag allows you define the mime-type of the contained data so we're being really explicit about what the data is and how it can be used.

To me, that feels quite clean.


Roland Collins
Jun 5, 2009 at 1:44 PM // reply »
31 Comments

I absolutely agree that the script tag version is less dirty :)

I was going to suggest maybe just using comments, but it looks like you beat me to it!

http://www.bennadel.com/index.cfm?dax=blog:1563.view

Seems like it's more difficult to impliment though.

I've just recently been utilizing jQuery too, and it's been very interesting. Lots of ways to do things, and no real best practices have been developed. Glad to see I'm not plumbing the depths alone!


Jun 5, 2009 at 2:07 PM // reply »
6,371 Comments

@Roland,

I like the comment approach, but I like the script tag even more as I think the "intent" of the script tag is more properly aligned with data contained within it than with HTML comments.


Jun 5, 2009 at 2:25 PM // reply »
10 Comments

"This metadata() plugin seems pretty cool, so I looked it up to see how it worked (I like to dig into cool things)."

Funny, I could have sworn Todd Raffery and I tweeted you about the metadata() plugin when you were trying out the data() function in jQuery many moons ago. Weren't you listening?? :)


Jun 5, 2009 at 2:32 PM // reply »
6,371 Comments

@Brian,

That sounds about right :) I guess, what I got jazzed up about this time was the use of the Script tag more than anything else.


David McGuigan
Jun 5, 2009 at 4:41 PM // reply »
63 Comments

Speaking of which, I was just about to ask you whether you wouldn't agree that the data( ) function seems a lot more maneuverable and productive than this approach?

To me having to contextualize the information you're storing with a script tag and mime type feels so verbose it kind of stings. It's just as easy to inject an invisible span or other container to keep yourself in the usual.

Before I found out about data( ) ( from your blog I might add ), I used to just pop invisible spans sibling or child to whatever structures I wanted to operate on and it worked beautifully.

Ex:
<div id="scripts">
<script type="text/plain">
Plain text in script tag.
</script>
<script type="text/plain">
More plain text in script tag.
</script>
</div>

Becomes:
<div id="scripts">
<span>Plain text in script tag</span>
<span>More plain text in script tag.</span>
</div>

And you'd just use the html( ) method ( just like you would with your script tags ) to retrieve the data.

Interested to hear your thoughts. Hopefully I haven't missed the point, which seems like to store data contextual to some other data in order to simplify identification and communication across an application.


Jun 5, 2009 at 6:57 PM // reply »
6,371 Comments

@David,

I think from a usability standpoint, there is no real difference between the SPAN approach and the SCRIPT approach - in the end, you're just pulling html() out of either of them.

But, there are a few things I like about the SCRIPT approach over the SPAN approach:

* Script is inherently not rendered (Span you would have to hide via CSS).

* Script has an inherent mime-type definition (Type attribute) which could be used to programmatically consume (ex. if type is "application/json", eval() data before returning it, otherwise return as string). (Span has no inherent data type other than string).

So, that's why I am warming up to this a lot. But, like I said, ultimatley, you are just getting data via html().

Once you have that data, though, I definitely agree that you would use the data() method to bind it to a DOM element so that it could be re-addressed later without re-parsing.


Jun 8, 2009 at 10:23 AM // reply »
6,371 Comments

I put together an example of this in conjunction with an AJAX call to return HTML table data:

http://www.bennadel.com/blog/1604-Using-Script-Tags-As-Data-Contains-In-AJAX-Powered-jQuery.htm

There were some oddities in the way the script tags get placed during the append() method.


Jun 9, 2009 at 5:46 PM // reply »
2 Comments

One of my favorite methods of the metadata plugin is with SerializeJSON and your favourite QueryToStruct implementation. If you are iterating through a query, it is easy to very tightly couple your data with your dom elements and spare yourself additional traversal later on when you need access to additional info from the query.

John Resig put together a pretty interesting implementation of micro-templating using the mime type on script blocks...
http://ejohn.org/blog/javascript-micro-templating/

--adam


Jun 10, 2009 at 5:07 PM // reply »
6,371 Comments

@Adam,

I think I've seen that post before - but long before I really understood using Script tags as data containers. I will definitely re-examine it, thanks.


Oct 15, 2009 at 7:55 PM // reply »
1 Comments

Hi!

I would like to know how would you use this approach if u needed to store data, for example, for each option in a select box.

Ex:
<select>
<option value=1>Eggs</option>
<option value=2>Cheese</option>
<option value=3>Milk</option>
</select>

In my case, i need to pass the value(money) each one costs. The solution i have found is to use de data-* attribute, but i dont know if this approach has issues.

Ex:
<select>
<option value=1 data-cost='5.20'>Eggs</option>
<option value=2 data-cost='2.40'>Cheese</option>
<option value=3 data-cost='1.73'>Milk</option>
</select>

Remember that this is just one of many selects dinamically generated at the server side and sent via AJAX to JS.

Thanks!


Oct 31, 2009 at 5:24 PM // reply »
6,371 Comments

@Daniel,

Yeah, you probably can't use this for OPTION elements. But, using the HTML5-friendly "data-" attribute, you should be good. You could also look into the metaData jQuery plugin which allows you to use CSS as well as other attributes to store meta data.


Post Comment  |  Ask Ben

Recent Blog Comments
Jill
Nov 7, 2009 at 7:58 AM
How To Unformat Your Code (Like A Pro)
LMAO - this was pretty funny! I have to admit - I also love to reformat code so I can read it. My boss used to tell me to leave my OCD at home. Now I don't feel so bad after reading everyone else' ... read »
Nov 6, 2009 at 10:10 PM
How To Unformat Your Code (Like A Pro)
The timing of this post is just uncanny. I spent the last 15-20 minutes manually un-formatting my "Ben Nadel" style code within a CFC of mine. I was really digging the readability a few weeks ago, bu ... read »
Roe
Nov 6, 2009 at 5:11 PM
Passing Arrays By Reference In ColdFusion - SWEEET!
ArraySort also reorders the results of these java obj's ... read »
Nov 6, 2009 at 4:53 PM
How To Unformat Your Code (Like A Pro)
I tried to go *back* the other way. Adding formatting is actually a much more complicated problem than removing formatting. Anyway, here is what I could put together with a minimal amount of time: ... read »
Asaf
Nov 6, 2009 at 2:35 PM
ColdFusion GetPageContext() Massive Exploration
Hi, I actually found this post useful. I recently acquired a SSL certificate for my website and when I switched over to HTTPS Internet Explorer would throw an error when trying to download a dynamic ... read »
Nov 6, 2009 at 2:19 PM
How To Unformat Your Code (Like A Pro)
@Chuck, @Nathan, Well, now I feel like it's a challenge.... I accept. ... read »
Nathan Stanford
Nov 6, 2009 at 2:06 PM
How To Unformat Your Code (Like A Pro)
@Chuck, I would love it as well. I was not joking I am very serious I love well formatted code. ... read »
Chuck
Nov 6, 2009 at 1:54 PM
How To Unformat Your Code (Like A Pro)
Ben great job, I happen to like your coding style and find it very easy to understand and follow. @Nathan, I totally agree, I (like the rest of you I assume) am pretty meticulous when it comes to c ... read »