Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at CFUNITED 2010 (Landsdown, VA) with: Ray Camden and Todd Sharp

jQuery And Script Tags As Data Containers

By Ben Nadel on

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.

Tweet This Deep thoughts by @BenNadel - jQuery And Script Tags As Data Containers Thanks my man — you rock the party that rocks the body!



Reader 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>

@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.

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

@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.

@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.

@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,

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.

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!

@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.

"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?? :)

@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.

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.

@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.

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

@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.

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!

@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.

@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.