Learning jQuery, Day 13: Adding Metadata
In earlier posts on this topic, I suggested that you split your "view" into two files -- one that is pure HTML (and the CFML you may need to process the view) and another one that holds your JavaScript and jQuery. One of the nice features of this is that it allows for unobtrusive JavaScript -- meaning that there's no JavaScript mixed in with HTML, making it possible (if you wish) to have a site that works both with JavaScript enabled and disabled.
Today, let's see how we can pass information to jQuery that it may need to do its job.
I'll start with a simple "employees" database table with the following columns:
- id
- firstName
- lastName
- ext
- status
I want an equally simple page that lists employees' first and last names, and provides for a drilldown for more info on a particular employee. Pretty standard stuff. You can see it running at http://dev.citymind.com:8500/test/blog_jquery/day13/index.cfm.
Here's the code for "index.cfm"
[Disclaimer: this code is written to teach jQuery as succinctly as possible. For that reason, it employs some "not-so-great" techniques, such as including a query in a display page.]
SELECT
id,
firstName,
lastName,
ext,
status
FROM
employees
ORDER BY
lastName ASC
</cfquery>
<table id="employees_table">
<cfoutput query="q">
<tr class="_employee">
<td>#lastName#</td>
<td>#firstName#</td>
</tr>
</cfoutput>
</table>
<div id="employee_detail"></div>
<cfinclude template="index.pgm">
Note that there are no hrefs and no JavaScript on this page. To enable the drilldown feature, I'm including "index.pgm". Let's start by looking at some incomplete code for that page.
<script type="text/javascript" src="jquery.metadata.pack.js"></script>
<script type="text/javascript">
$('._employee').click(function()
{
var detailString = "[firstName] [lastName] can be reached at extension [ext]. This employee is currently in [status].";
$('#employee_detail').html(detailString);
}
);
</script>
You'll notice that I've included the base jQuery file from Google's content delivery network (CDN), as well as a file called "jquery.metadata.pack.js". Those are the external JavaScript files I'll need for this example.
Next, I have a SCRIPT tag with some custom JavaScript. This script tells jQuery: "When someone clicks an element with a class of "_employee", create a "detailString" and put it in the element with an id of "employee_detail".
But if you notice the detailString, you'll see that it's not going to do what we need. It has placeholders (those variable names wrapped in square braces) for employee information, but no way to access information for the employee clicked.
I could, of course, make accessible the id of the employee, with which I could do another query for employee details -- and that's just what I'd normally do. But here I've chosen a different way, in order to show you how you can make information available using something called "metadata".
To make this work, I'm going to make a change to my index.cfm page:
<tr class="_employee {firstName : '#firstName#', lastName : '#lastName#', ext : '#ext#', status : '#status#'}">
<td>#lastName#</td>
<td>#firstName#</td>
</tr>
</cfoutput>
What's this -- JSON added to the class attribute? Well, yes. I'm going to use the metadata plugin to get to this data. It's placed in the "class" attribute because this is something all HTML elements have.
Now, I'm going to fix that "detailString":
var detailString = md.firstName + ' ' + md.lastName + ' can be reached at extension ' + md.ext +'. This employee is currently in ' + md.status + '.';
$('#employee_detail').html(detailString);
To make this work, I added in the line:
This is a call to the metadata plugin, telling it to extract the information encoded into the JSON string in the "class" attribute. Once this is done, I have access to a JavaScript object, "md", whose properties I can call to get the required information.
Are we really doing all this just to avoid a call to the database? No. This was just the best (although admittedly not wonderful) example I could come up with that wouldn't require a good deal more code and lengthy explanations. A more real-world application might be to extract the user's name and id, and from that...
a. creating a tab titled "Details on Anne Baker" (for example) b. making an Ajax call to get full details on Anne c. inserting that information into the newly-created tab
A couple of notes.
1. I could have put some information into a "title" or an "alt" tag, but there are problems with this. First, not all HTML elements have these as valid attributes. That can cause the browser to go into "quirks mode", making it render more slowly. Second, some browsers will display information in one of these tags to appear as a "tooltip", which may not be desired behavior.
2. Any strings placed in the "class" attribute look to CSS like classes. This could cause a problem if you have a normal CSS class called, for example, "firstName". My solution to that is to prefix all my real CSS classes with an underscore.


[url=http://www.google.com/profiles/irodibaikepet] googler [/url][url=http://www.youtube.com/user/gyher13] gyher [/url][url=http://www.linkedin.com/in/2ynet] linkedim [/url][url=http://www.viddler.com/explore/polerm] viddler [/url]
<a href=http://www.linkedin.com/in/2ynet>" target="_blank">http://www.linkedin.com/in/2ynet> linkedim </a><a href=http://www.youtube.com/user/gyher13>" target="_blank">http://www.youtube.com/user/gyher13> gyher </a><a href=http://www.google.com/profiles/irodibaikepet> googler </a><a href=http://www.viddler.com/explore/polerm> viddler </a>
<div class="person">
<!-- {name: "Adrian", stuff: "nonsense"} -->
<someother-elements />
</div>
The downside to this is, jQuery doesn't let you select comment nodes. I had to drop back to regular JS to get at the data. The upside? It didn't feel as messy as lacing class attributes with the data.
Next time I need to do this I think I'll use the metadata plugin.