views:

2935

answers:

14

I'm making a page which has some interaction provided by javascript. Just as an example: links which send an AJAX request to get the content of articles and then display that data in a div. Obviously in this example, I need each link to store an extra bit of information: the id of the article. The way I've been handling it in case was to put that information in the href link this:

<a class="article" href="#5">

I then use jQuery to find the a.article elements and attach the appropriate event handler. (don't get too hung up on the usability or semantics here, it's just an example)

Anyway, this method works, but it smells a bit, and isn't extensible at all (what happens if the click function has more than one parameter? what if some of those parameters are optional?)

The immediately obvious answer was to use attributes on the element. I mean, that's what they're for, right? (Kind of).

<a articleid="5" href="link/for/non-js-users.html">

In my recent question I asked if this method was valid, and it turns out that short of defining my own DTD (I don't), then no, it's not valid or reliable. A common response was to put the data into the class attribute (though that might have been because of my poorly-chosen example), but to me, this smells even more. Yes it's technically valid, but it's not a great solution.

Another method I'd used in the past was to actually generate some JS and insert it into the page in a <script> tag, creating a struct which would associate with the object.

var myData = {
    link0 : {
        articleId : 5,
        target : '#showMessage'
        // etc...
    },
    link1 : {
        articleId : 13
    }
};

<a href="..." id="link0">

But this can be a real pain in butt to maintain and is generally just very messy.

So, to get to the question, how do you store arbitrary pieces of information for HTML tags?

+1  A: 

I know that you're currently using jQuery, but what if you defined the onclick handler inline. Then you could do:

 <a href='/link/for/non-js-users.htm' onclick='loadContent(5);return false;'>
     Article 5</a>
tvanfosson
+12  A: 

Which version of HTML are you using?

In HTML 5, it is a totally valid to have custom attributes prefixed with data-, e.g.

<div data-internalid="1337"></div>

In XHTML, this is not really valid. If you are in XHTML 1.1 mode, the browser will probably complain about it, but in 1.0 mode, most browsers will just silently ignore it.

If I were you, I would follow the script based approach. You could make it automatically generated on server side so that it's not a pain in the back to maintain.

DrJokepu
Sadly, of course, html5 is not heavily supported by... ...well, any browser, essentially. It's not even fully completed spec yet anyway.
Tchalvak
@Tchalvak: True, but this bit will work on most browsers, none the less.
DrJokepu
+6  A: 

Arbitrary attributes are not valid, but are perfectly reliable in modern browsers. If you are setting the properties via javascript, than you don't have to worry about validation as well.

An alternative is to set attributes in javascript. jQuery has a nice utility method just for that purpose, or you can roll your own.

Eran Galperin
+3  A: 

A hack that's going to work with pretty much every possible browser is to use open classes like this: <a class='data_articleid_5' href="link/for/non-js-users.html"> This is not all that elegant to the purists, but it's universally supported, standard-compliant, and very easy to manipulate. It really seems like the best possible method. If you serialize, modify, copy your tags, or do pretty much anything else, data will stay attached, copied etc. The only problem is that you cannot store non-serializable objects that way, and there might be limits if you put something really huge there.

A second way is to use fake attributes like <a articleid='5' href="link/for/non-js-users.html"> This is more elegant, but breaks standard, and I'm not 100% sure about support. Many browsers support it fully, I think IE6 supports JS access for it but not CSS selectors (which doesn't really matter here), maybe some browsers will be completely confused, you need to check it. Doing funny things like serializing and deserializing would be even more dangerous.

Using ids to pure JS hash mostly works, except when you try to copy your tags. If you have tag <a href="..." id="link0">, copy it via standard JS methods, and then try to modify data attached to just one copy, the other copy will be modified. It's not a problem if you don't copy tags, or use read only data. If you copy tags and they're modified you'll need to handle that manually.

taw
+4  A: 

Why not make use of the meaningful data already there, instead of adding arbitrary data?

i.e. use <a href="/articles/5/page-title" class="article-link">, and then you can programmatically get all article links on the page (via the classname) and the article ID (matching the regex /articles\/(\d+)/ against this.href).

Ant P.
Problem with this is that it's also not really extensible
ehdv
A: 

One possibility might be:

  • Create a new div to hold all the extended/arbitrary data
  • Do something to ensure that this div is invisible (e.g. CSS plus a class attribute of the div)
  • Put the extended/arbitrary data within [X]HTML tags (e.g. as text within cells of a table, or anything else you might like) within this invisible div
ChrisW
+3  A: 

Just another way, I personally wouldn't use this but it works (assure your JSON is valid because eval() is dangerous).

<a class="article" href="link/for/non-js-users.html">
    <span style="display: none;">{"id": 1, "title":"Something"}</span>
    Text of Link
</a>

// javascript
var article = document.getElementsByClassName("article")[0];
var data = eval(article.childNodes[0].innerHTML);
Luca Matteis
+1 for lateral thinking. I agree that I probably wouldn't want to use this method, but it's a vaguely viable option!
nickf
ehdv
+7  A: 

If you are using jQuery already then you should leverage the "data" method which is the recommended method for storing arbitrary data on a dom element with jQuery.

To store something:

$('#myElId').data('nameYourData', { foo: 'bar' });

To retrieve data:

var myData = $('#myElId').data('nameYourData');

That is all that there is to it but take a look at the jQuery documentation for more info/examples.

Prestaul
A: 

As long as you're actual work is done serverside, why would you need custom information in the html tags in the output anyway? all you need to know back on the server is an index into whatever kind of list of structures with your custom info. I think you're looking to store the information in the wrong place.

I will recognize, however unfortunate, that in lots of cases the right solution isn't the right solution. In which case I would strongly suggest generating some javascript to hold the extra information.

Kris
how are you supposed to pass data to javascript then?
nickf
A: 

At my previous employer, we used custom HTML tags all the time to hold info about the form elements. The catch: We knew that the user was forced to use IE.

It didn't work well for FireFox at the time. I don't know if FireFox has changed this or not, but be aware that adding your own attributes to HTML elements may or may-not be supported by your reader's browser.

If you can control which browser your reader is using (i.e. an internal web applet for a corporation), then by all means, try it. What can it hurt, right?

Jerry
A: 

As a jQuery user I would use the Metadata plugin. The HTML looks clean, it validates, and you can embed anything that can be described using JSON notation.

Robin Smidsrød
A: 

I advocate use of the "rel" attribute. The XHTML validates, the attribute itself is rarely used, and the data is efficiently retrieved.

demonkoryu
cant do that id break the nofollow attribute on the links
Carter Cole
A: 

In regards to what Robin said about the Metadata plugin... it isn't exactly worth an additional 37kb script though is it? :/

I tend to use value="" but as you say, XHTML complains about it... is it that important to validate? How about a hidden input field? or perhaps just passing it in jQuery?

Intellix
A: 

So there should be four choices to do so:

  1. Put the data in the id attribute.
  2. Put the data in the arbitrary attribute
  3. Put the data in class attribute
  4. Put your data in another tag

http://www.shanison.com/?p=321

Shanison