Raymond Camden's Blog Rss

HTML5 Data Attribute Example

4

Posted in jQuery, JavaScript, HTML5 | Posted on 11-03-2011 | 4,239 views

My readers are probably sick and tired of me gushing over data attributes, and for that, I apologize. I'm just a huge fan of practical, useful solutions, and no, I'm not going to use this as opportunity to complain about how silly Canvas is again. Rather, I thought I'd whip up another simple example of how you can make use of data attributes in your shiny Ajax-enabled web sites.

If you don't remember what data attributes are, here's a quick reminder. Data attributes are a way to add ad hoc data to your DOM. By prefixing an attribute with data- in front of your name/value pair, your have HTML that is still valid no matter what name you use. So for example:

view plain print about
1<img src="something" data-nsfw="true">

There is no data-nsfw attribute for the image tag, but because I began the attribute with data-, it's valid. Another example:

view plain print about
1<img src="something" data-nsfw="true" data-hires="someurl">

In both examples, the browser blissfully ignores the custom attributes, but you can write your own code to do whatever you want with it. This comes in handy in numerous situations, but here's one simple example. Imagine I'm selecting data from a table that includes price information. To make it pretty, I'll wrap the output of the price in a function to render it as a currency. Here's an example in ColdFusion:

view plain print about
1Price: #dollarFormat(price)#<br/>

For the hell of it, here's the PHP version of it:

view plain print about
1echo money_format('%i', $price) . "\n";

This outputs something like : $12,3900.11. What if you wanted to work with this price in JavaScript but treat it as a number? You would need to strip out the currency, possibly even the commas first. Instead of worrying about that, what if we used data attributes to store the "naked" price as a simple number? This will be hidden from the end user (technically not hidden - it will be available in view source) but will be available for our code. Here's an example. The code below loops over a query of art work. (I'll show the entire template in a bit.)

view plain print about
1<cfoutput query="getArt">
2    <div class="artPiece" data-id="#artid#" data-price="#price#">
3        
4        <h2>#artname#</h2>
5        Price: #dollarFormat(price)#<br/>
6        Media: #mediatype#<br/>
7        Artist: #firstname# #lastname#<br/>
8        #description#<br/>
9        <img src="/cfdocs/images/artgallery/#largeimage#">
10    </div>
11</cfoutput>

As you can see, I've included two data attributes in my div tag. One of the primary key of the record and one for the price. To be clear, I could have used other methods. I could have used a hidden form field for example. But this is much cleaner. Grabbing the values is a matter of simple JavaScript, but jQuery makes it even easier. Here's the complete template:

view plain print about
1<!--- get art work --->
2<cfquery name="getArt" datasource="cfartgallery">
3select    art.artid, art.artname, art.description, art.price, art.largeimage,
4        artists.firstname, artists.lastname,
5        media.mediatype
6        from art
7        join artists on art.artistid = artists.artistid
8        join media on art.mediaid = media.mediaid
9</cfquery>
10
11<html>
12    
13    <head>
14        <title>Data Example</title>
15        <link rel="stylesheet" href="http://twitter.github.com/bootstrap/1.3.0/bootstrap.min.css" />
16        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
17
18        <style>
19        .artPiece {
20            margin: 12px;    
21            border-style:solid;
22     border-width:thin;
23            width: 230px;
24            padding: 5px;
25            float: left;
26        }
27        
28        </style>
29        <script type="text/javascript">
30        $(function() {
31            $(".artPiece").click(function() {
32                var selectedId = $(this).data("id");
33                var selectedPrice = $(this).data("price");
34                console.log(selectedId+" "+selectedPrice);
35            });            
36        });    
37        </script>
38    </head>
39    
40    <body>
41        
42        <div class="container">
43            
44        <h1>Art Work</h1>
45        
46        <cfoutput query="getArt">
47            <div class="artPiece" data-id="#artid#" data-price="#price#">
48                
49                <h2>#artname#</h2>
50                Price: #dollarFormat(price)#<br/>
51                Media: #mediatype#<br/>
52                Artist: #firstname# #lastname#<br/>
53                #description#<br/>
54                <img src="/cfdocs/images/artgallery/#largeimage#">
55            </div>
56        </cfoutput>
57        
58        </div>
59        
60    </body>
61    
62</html>

You can ignore the SQL and most of the formatting. Focus on the fact that I've got a click handler on my div. Grabbing my two values is as simple as using jQuery's data method. You can demo this below.

Comments

[Add Comment] [Subscribe to Comments]

Nice. The way ColdFusion talks to JavaScript is through the DOM. ColdFusion populates data- attributes and input values before the page is loaded. JavaScript can examine them after the page is loaded. JavaScript can then call a .cfc via AJAX to talk back to ColdFusion.
I have often doing things like <td id="id_1234"> and then used javascript's split(tmpid,'_') function to parse that.

This example makes that much cleaner:
$(this).data("price"); <-- Like It!
Ray - I have been doing this technique for a while now, but I have not been prefixing the attributes with "data-". For example:

<tr id="id#region_id#" pkid="#region_id#" rowid="#CurrentRow-1#">

Then when a user clicks a button in the row, I use this script:

var $tr = $(btn).closest("tr");
var pkid = $tr.attr("pkid");
var rowid = $tr.attr("rowid");
var ROW = qryRows.DATA[rowid];

Where "qryRows" is a JSON serialized query. Is there any downside to this method over the "data-" prefix? I haven't seen any yet, but your comment " you have HTML that is still valid" caused me to blink.
It may work, but is not considered valid HTML since those attributes are not in the HTML spec.

Now - I've been known to say practicality should trump spec - but in this case we have an easy way to be in spec - hence my recommendation to use data-* instead.