I'm working on a new project now (Picard FTW - Engage!) and it involves converting some existing JavaScript. The "old" JavaScript works fine, but is very difficult to get to and also suffers from the fact that it isn't jQuery. That's a huge problem if you ask me. So as I work through the project I'm slowly converting various dynamic elements into ColdFusion. One of those elements was pretty interesting. A list of fields had an associated piece of metadata. Each piece was represented in simple text. Next to it was an edit link. Clicking edit changed the plain text into a drop down. I reworked this into jQuery and this is what I came up.
First let's define the data. My form will have a list of movies. For each movie there is a simple rating system based on 4 values: Hated It, Disliked It, Liked It, Loved It. It is assumed that the user has already selected some values which end up being rendered as hidden form fields:
star wars: <span class="changeable"><input type="hidden" name="starwars" value="4">Loved It - <a href="" class="edit">edit</a></span><br/>
star trek: <span class="changeable"><input type="hidden" name="startrek" value="3">Liked It - <a href="" class="edit">edit</a></span><br/>
This wouldn't normally be hard coded - it would come in dynamically via ColdFusion. But you get the idea. Notice that I've wrapped the hidden field, the current text, and a link within a span. Ok, now for the jQuery:
$(document).ready(function() {
//used for our drop downs
var values = [1,2,3,4]
var labels = ["Hated It","Disliked It","Liked It","Loved It"]
$(".changeable a.edit").click(function() {
//find the hidden item
var hiddenItem = $("input:hidden", $(this).parent())
//get the current val
var currentVal = hiddenItem.val()
//get the name
var currentName = hiddenItem.attr("name");
//now we can draw our drop down and select the right val
var s = "<select name=""+currentName+"">";
//hard coded values for our drop down
for(var i=0;i<values.length;i++) {
s+= "<option value="" + values[i] + """
if(currentVal == values[i]) s+= " selected"
s+= ">" + labels[i] + "</option>"
}
s += "</select>"
//now replace
$(this).parent().html(s)
return false
})
})
First notice I've got two hard coded values. These represent the values and labels for the drop down I'll build later. Again, this would probably be dynamic. Don't forget ColdFusion provides a nice utility function, toScript, to make it easy to convert ColdFusion variables into JavaScript.
Now let's walk through the main function. My selector looks for links with the class edit with DOM items with the class changeable. I've binded to the click event for the link. This matches the link within the span I used. But I need to get information from the rest of the span. So I grab a pointer to the hidden form field by doing a selector against the parent of the link. Does that make sense? Ie: "jQuery, within the parent of what you just found please look for a hidden input field." Once I have that I can get the value as well as the name.
Once I have the name, and the current value, building the drop down is just a matter of string builder. I use the values/labels variables and just create the select. When done I can replace the link for the span. Remember that $(this) represents the original link so $(this).parent() will be the span.
You can see a demo of this here: http://www.coldfusionjedi.com/demos/changedropdown/test.cfm
And here is the complete script:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script>
$(document).ready(function() {
//used for our drop downs
var values = [1,2,3,4]
var labels = ["Hated It","Disliked It","Liked It","Loved It"]
$(".changeable a.edit").click(function() {
//find the hidden item
var hiddenItem = $("input:hidden", $(this).parent())
//get the current val
var currentVal = hiddenItem.val()
//get the name
var currentName = hiddenItem.attr("name");
//now we can draw our drop down and select the right val
var s = "<select name=""+currentName+"">";
//hard coded values for our drop down
for(var i=0;i<values.length;i++) {
s+= "<option value="" + values[i] + """
if(currentVal == values[i]) s+= " selected"
s+= ">" + labels[i] + "</option>"
}
s += "</select>"
//now replace
$(this).parent().html(s)
return false
})
})
</script>
</head>
<body>
<form method="post">
star wars: <span class="changeable"><input type="hidden" name="starwars" value="4">Loved It - <a href="" class="edit">edit</a></span><br/>
star trek: <span class="changeable"><input type="hidden" name="startrek" value="3">Liked It - <a href="" class="edit">edit</a></span><br/>
<input type="submit" value="click me like you mean it">
</form>
<cfif not structIsEmpty(form)>
<cfdump var="#form#" label="form">
</cfif>
</body>
</html>