jQuery And Script Tags As Data Containers

Posted June 5, 2009 at 9:59 AM by Ben Nadel

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.

  • <!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.




Reader Comments

Jun 5, 2009 at 11:04 AM // reply »
67 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 »
11,238 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 »
15 Comments

Very Cool. I love jQuery.


Jun 5, 2009 at 12:51 PM // reply »
7 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 »
11,238 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.


Jun 5, 2009 at 1:22 PM // reply »
45 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 »
11,238 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.


Jun 5, 2009 at 1:29 PM // reply »
45 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 »
11,238 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.


Jun 5, 2009 at 1:44 PM // reply »
45 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 »
11,238 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 »
26 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 »
11,238 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.


Jun 5, 2009 at 4:41 PM // reply »
149 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 »
11,238 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 »
11,238 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 »
7 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 »
11,238 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 »
11,238 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.


Jul 8, 2010 at 6:37 PM // reply »
1 Comments

Thanks for this post, it gave me a clean solution for some pages where the JSON payload for a JavaScript grid was being put into a hidden textarea (and the resulting problems):
http://tech.agilitynerd.com/embedding-json-within-generated-html

Thanks again.


Jul 9, 2010 at 10:17 AM // reply »
11,238 Comments

@Steve,

Very cool my man. As I said on your blog, I've been using and loving the use of Script tags for all kinds of data containers.


Apr 15, 2011 at 8:42 AM // reply »
1 Comments

@Aaron,

it's not jQuery specific at all.



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 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
May 20, 2013 at 4:29 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, That's if you're trying to reference a specific row. In this case, we're trying to reference the entire query column as one cohesive value. So, you are correct that if you wanted to output a ... read »
May 20, 2013 at 4:24 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I thought when you used array notation to reference queries you always had to have the row or it would throw a similar error as well? ... read »
May 20, 2013 at 11:45 AM
Using jQuery's Animate() Step Callback Function To Create Custom Animations
This is really useful. I found out that you don't actually have to use a dummy css property (surprisingly). To animate a property in a linear-gradient for instance I did this this.css('someLinearGra ... read »
May 20, 2013 at 10:51 AM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Josh, Oh snap! You're totally right! I'm not sure I've ever tried that. I did know that you can call a number of other array-methods on ColdFusion query columns: http://www.bennadel.com/blog/167 ... read »
May 20, 2013 at 10:45 AM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Ben - I believe you can achieve the same functionality with ColdFusion's built in ArrayToList() function. ArrayToList( users[ "id" ] ); ... read »
May 20, 2013 at 10:21 AM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
Is there any error logging and handling framework in angularjs, if not then in what way I can do this. ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools