views:

115

answers:

8

What I need to do is be able to store some piece of data about an element.

For example, lets say I have a list item <li>, and I want to store some data about it in the element, like "This is element 1 from XYZ".

The only way I know how to do this (which I don't want to do if I can avoid) is this:

<li id='item1'>
  Item 1
  <!--This is element 1 from XYZ-->
</li>

<script>
  // read it something like this
  var e = document.getElementById('item1').innerHTML; 
  // then parse out the comment, etc.
  // --
</script>

What I really want is something like this (which I am fairly certain is not possible):

// example
<li id='item1' userdata='This is element 1 from XYZ'>Item 1</li>

.. of course, I would like to be able to access it somehow via javasscript.

Alternatively, is there some other way to achieve this?

Thanks -

+4  A: 

You can't add arbitrary elements to HTML. Well you can but it won't be valid and beheaviour is undefined. For this kind of thing I tend to use jQuery. It has a data() call that can add arbitrary data to an element. I believe it encodes it in the class attribute but the implementation is not important.

You could do this yourself but why bother? It's easy to get wrong by putting the wrong characters in, not correctly escaping/unescaping data or inadvertently destroying informatino. Instead just do:

$("#item1").data({source: "Thsi is element 1 from XYZ"});
cletus
+12  A: 

You can access your userdata="" attribute from JavaScript. Just do:

var theData = document.getElementById('item1').getAttribute('userdata');

If you want to do it the HTML5 way, then you would use attributes named data-*, e.g.:

<li id='item1' data-foo='This is element 1 from XYZ'>Item 1</li>

that way it will still be valid (i.e., it'll make you feel better for not using an invalid attribute). New browsers will support accessing the data-* attributes like so:

var theData = document.getElementById('item1').data.foo;

but I don't think that is implemented widely enough to rely upon yet.

If you do want to store the data in a comment (although I'd advise going the attribute route instead) you could do something like:

var e = document.getElementById('item1');
var n = e.firstChild;
while (n && n.nodeType != Node.COMMENT_NODE) {
    n = n.nextSibling;
}
// now n.nodeValue will have the comment contents

(No guarantees about whether IE likes any of the above.)

heycam
+1 For mentioning the *valid* HTML5 data attributes. Great answer!
Doug Neiner
+1 too for HTML5
Anurag
Wow - what an excellent answer, plus the HTML5 mention is very useful. Thanks very much!
OneNerd
How widely implemented is setUserData?
Dominic Cooney
Dominic, of the major five browsers, it seems only Firefox supports it.
heycam
A: 

If you don't need the HTML to be valid, you can make any attribute you want, and you can access it in Javascript by calling the getAttribute method.

SLaks
A: 

You can add a nested invisible element with an id and your data as the innerText. Use the style attribute to make sure it's invisible.

But it all really depends on what you're trying to achieve. Could you elaborate more?

Assaf Lavie
+1  A: 

Since you can accept adding comments, a better solution would be to add a span element with the content you wanted..

<span class="data">.....</span>

you define your data class to have display:none and it is invisible ...

this way you can have access to it with the normal DOM traversing methods..

Gaby
A: 

You can use setUserData() and getUserData() function http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#Node3-setUserData

For example:

<html>
<head>
    <script type="text/javascript">
        function set(){
            var a = document.getElementById("testElement");
            a.setUserData("testData", "Some text", null);
        }

        function get(){
            var a = document.getElementById("testElement");
            alert(a.getUserData("testData"));
        }
    </script>
</head>
<body>
    <span id="testElement"/>
    <form>
        <input type="button" value="setUserData" onclick="set()"/>
        <input type="button" value="getUserData" onclick="get()"/>
    </form>
</body>

hvtuananh
A: 

// If you want to include data in the html why not give it its own node?

.hiddendata{
 display: none
}

<li id= 'item1'> 
Item 1
<span class= "hiddendata"> This is element 1 from XYZ</span> 
</li> 

function readHiddenData(who){
 var A= [], n= who.firstChild;
 while(n){
  if(n.className= 'hiddendata'){
   A[A.length]= n.textContent || n.innerText || '';
  }
  n= n.nextSibling;
 }
 return A;
}

function showHiddenData(who){
 var n= who.firstChild;
 while(n){
  if(n.className= 'hiddendata'){
   n.style.display= "inline"
  }
  n= n.nextSibling;
 }
}
kennebec