Recently, I discussed the pitfalls of using custom HTML attributes and “expando” DOM properties to store per-element data. Thanks to the comments on that post I now understand that doing so is sometimes hard to avoid. Some people resort to using jQuery’s “metadata” plugin which can massively simplify the process of adding metadata (i.e. data about data). I’ve been meaning to post a technique I’ve been using recently; keeping data in HTML comments and then extracting it and tying it to the closest (parent) element.
With this technique you can do the following:
<div id="foo"> <!-- { someData: 123, aString: "bar" } --> <p> ... regular content ... </p> </div> <!-- Regular comments can still be used --> <p><!--{specialID:1234}-->... comment-data is tied to the parent element...</p> |
Using the “commentData” function you can extract that information and use it within your JavaScript, e.g.
var foo = document.getElementById('foo'); var fooData = commentData( foo ); // => {someData: 123, aString: "bar"} fooData.someData; // <= 123 |
Download “commentData” from Github
Thanks for reading! Please share your thoughts with me on Twitter. Have a great day!
This reminds me of comment annotations found in server-side languages and frameworks such as Recess – they allow embeddable metadata and declarative calls to functions and specific functionality through a DSL of sorts, resting in the comments.
For instance, in Recess, which is an MVC framework, you can specify the routing patterns of controllers and individual methods by using the !Route annotation. This format is used extensively throughout the framework from the routing system to defining relationships in Models to external plugins and extensions – it’s a pretty clever technique and makes the code a lot easier to read and understand.
Coming back to JavaScript, this technique could be applied to HTML tags, using your technique here. You could add event handlers to elements, call functions directly on that element on page load and even automatically animate elements.
Using unobtrusive JavaScript you could define an event, methods or anything else you like to use later in your annotations:
And then put annotations in your HTML that define events, animations, method calls, or anything else that you like to bind to a specific element.
Of course this is all pseudo code for now, but it might be interesting to see how this could work effectively. As for semantics, well, you are marking up the data’s interactivity, so I don’t see how this couldn’t be a viable idea. Building this ‘layer’ on top of HTML to bridge HTML and JavaScript somewhat could be very interesting, and as it’s basic string manipulation parsing wouldn’t be too slow or difficult either!
Anyway, just an idea, I’d like to see this working. I’ll have a go writing something later to test it out.
Interesting idea Jamie. Adding events and carrying out other functions on the element is something I did consider, and it’s been done before by Toby Miller: http://www.tobymiller.com/articles/mootools_enhanced_elements/index.php
I think, maybe, what Toby’s done and what you’re suggesting is taking it one step too far though.
I mean, is doing this:
… really any better than this:
…?
Both methods are equally obtrusive IMO.
As far as I’m concerned, metadata is content and so having it lying around in the HTML is okay (not ideal, but okay). But, behavioural enhancements (event handlers, animation etc.) should be kept elsewhere.
I think there’s a line to be drawn.
HTML 5 makes it obsolete by defining data-* attributes.
@ab, nice of you to leave your real identity!
Tell me, how would you define a data structure like this with HTML5’s ‘data-*’ attributes? –
In the last code example, I think it’s
commentData()
instead ofparseData()
? 😉It should be fairly easy to modify this so that you can supply it with a jQuery selector or a jQuery object, which would be useful when the element doesn’t have an ID, but my brain isn’t working today.
Would this be easy enough?
Why would you want to store data inside HTML anyways? I don’t think I have/will ever come across a situation where I would have to do something like this.
@Lim, Sorry about that, just updated it. 🙂
@Jon, why would you want to supply it with a selector? The data is tied to the parent (
commentNode.parentNode
). This technique does not require the element to have an ID. The only reason I’ve given the element an ID in the example was to illustrate how you might extract that data via JavaScript.@Evan, Sometimes, you may need to have a large amount of data existing within the document so you can use it when the user interacts with the page – this is preferred over Ajax when you have a small dataset and when interactivity is likely. There are many different applications. Read:
– http://loadaveragezero.com/app/drx/Data_Formats/Metadata
– http://www.1729.com/blog/HtmlAnnotations.html
– http://www.mail-archive.com/[email protected]/msg06489.html
Also have a look at jQuery’s “metadata” plugin (created by John Resig himself) to see an alternative implemenation.
All I wanted to be able to do was this…
I’m probably just being thick but if each column had an ID then I could do this….
@Jon,
$(this)
is a jQuery object –commentData
requires a DOM element reference. Here, try this:Thanks James, excellent article and much better than what I was doing (lots of dives inside a hidden div).
@James, still, it just doesn’t seem right to me…
:)) You’ve got to be kidding me:
@prafuitu, lol, silly me! 😛
Another option…
http://docs.jquery.com/Internals/jQuery.data