Every so often, when in JavasScript-code-mode, there's the need to make some decisions based on data that's not available in the document itself. Say your templating engine comes up with the following HTML, which is basically a list of friends linking to their respective profiles;
Now you'd want to mix in some extra-js-fu, by displaying a mini profile when you click any of the links. For that you'll be using your AJAX-API that needs eg. a user-identification integer or string as parameter. How is your JavaScript gonna know what this userID is for each of the listed friends? Right, you need some extra information for this.
Different approaches
There's a few ways of including data you need on a js-application level to your DOM-tree, some of which I list here;
-
Hidden form elements:
You could nest some forms with hidden elements containing the data you need into your DOM. But I guess for the use case here, that would make your html quite cluttered and you'll have quite some overhead traversing the DOM to find the elements related to the click-event of your link. On the upside though, you can store about any value in those form elements as long as they're properly escaped. Example HTML:HTML: -
Custom attributes:
Why not just add some custom userID-attributes to the elements you need? It's very readable and flexible, it works in all browsers that support XHTML and - as with form elements - allows for about any type of text string, thus is an excellent solution. And in fact, the X in XHTML is for extensible right? But of course, there's the Standards Police™, who might not like that you're adding new custom attributes that aren't in the original specification, to put you off from using this technique. Example HTML:HTML:-
<a href="/wolksken" userid="1043">Laura Bogaert</a>
-
-
Abuse an existing attribute:
You could hide the fact you actually want to use custom attributes, by just abusing some of the existing ones. Let's for instance take the rel="" attribute; an existing attribute, available on anchors, left mostly unused; if we use it to store a userid in, validators won't complain, so we're all set? Well, quite an ugly hack, isn't it? Not semantic, not always available and you still have no easy solution for key-value pairs. Example HTML:HTML:-
<a href="/wolksken" rel="1043">Laura Bogaert</a>
-
-
(Ab)use your class-attribute:
There is one attribute that does fit for using to save data though, since it's available on every element, flexible enough, and it (can) even make sense on a semantic level. While class names will in 99% of the cases play a purely visual role, you could use them for application logic too. Isn't that what microformats are doing? Since you're using class names, you have to deal with some of it's limitations though; they can't have spaces, and some browsers might not like all characters. Example HTML:HTML:-
<a href="/wolksken" class="userid_1043">Laura Bogaert</a>
-
Each of these 4 techniques have their own reasons to exist, and I'm not here to tell you which one is best, or which one you should use. I'm here to share two helper methods I've written for the class names approach.
Extending Prototype with classname data helpers
So, we're adding some extra data to our class-attributes. The templating engine does this in the format of "
If we want to access these key-value pairs in JavaScript we go to the DOM-element, loop over it's class names, split the keys and values, and return the value for the queried key. Likewise you might want to have a class data setter method too.
For this I wrote two methods, getClassData(key) and setClassData(key, value), for Prototype, my weapon of choice for JavaScript development. These methods are getters and setters for those key-value pairs, and thanks to Element.addMethods, available on every DOM-element. Here's an example of it's use:
-
$$('ul.myfriends').first().observe('click', function(event) {
-
var userID = event.element().getClassData('userid');
-
alert(userID);
-
});
Here's the source code:
-
/**
-
* Extend all Prototype DOM-element with getClassData() and setClassData() methods
-
*
-
* @author Jurriaan Persyn - http://www.jurriaanpersyn.com
-
* @version 0.1
-
*/
-
Element.addMethods({
-
-
/**
-
* Returns a string stored in the classnames of a DOM-element in the form of "$key$glue$data"
-
*
-
* @param DOM-element element id or reference to a DOM-element
-
* @param string key the key of the classname
-
* @param string glue optional, default "_"
-
* @return mixed_var null or string
-
*/
-
getClassData: function(element, key, glue)
-
{
-
element = $(element);
-
if (!glue)
-
{
-
glue = "_";
-
}
-
key = key + glue;
-
var data = null;
-
element.classNames().each(function(className) {
-
if (className.substr(0, key.length) === key)
-
{
-
data = className.replace(key, "");
-
}
-
});
-
if (data)
-
{
-
data = decodeURIComponent(data);
-
}
-
return data;
-
},
-
-
/**
-
* Stores a string in the classnames of a DOM-element in the form of "$key$glue$data"
-
*
-
* @param DOM-element element id or reference to a DOM-element
-
* @param string key the key of the classname
-
* @param string data a string with some data
-
* @param string glue optional, default "_"
-
* @param element Returns the element itself to allow chaining
-
*/
-
setClassData: function(element, key, data, glue)
-
{
-
if (!glue)
-
{
-
glue = "_";
-
}
-
element = $(element);
-
-
var previousData = element.getClassData(key);
-
if (previousData)
-
{
-
previousData = encodeURIComponent(previousData);
-
element.removeClassName(key + glue + previousData);
-
}
-
-
data = encodeURIComponent(data);
-
element.addClassName(key + glue + data);
-
-
return element;
-
},
-
-
_eoo: true
-
-
});
Here's a seperate file with the script: classdata-extensions-01.js.
The getClassData will always return values as strings. You could build in some type-hinting methods, but you'd have to implement that same protocol in your templating engine too then, so I decided to leave it out here. The data value is now being url-escaped to add it to the classes, but of course there's some limitations there too.
Here's to hoping these 2 methods might provide you some use ...
[...] few weeks ago former colleague Jurriaan wrote a PrototypeJS extension to accessing data stored within classes of HTML elements. Basically it comes down to assigning extra classes (classes such as gender_male for example, which [...]
Posted by Bram.us » Accessing data saved in the class property of DOM-elements with jQuery on February 9th, 2009.