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:
2 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:
2
3 //used for our drop downs
4 var values = [1,2,3,4]
5 var labels = ["Hated It","Disliked It","Liked It","Loved It"]
6
7 $(".changeable a.edit").click(function() {
8 //find the hidden item
9 var hiddenItem = $("input:hidden", $(this).parent())
10 //get the current val
11 var currentVal = hiddenItem.val()
12 //get the name
13 var currentName = hiddenItem.attr("name");
14 //now we can draw our drop down and select the right val
15 var s = "<select name=\""+currentName+"\">";
16 //hard coded values for our drop down
17 for(var i=0;i<values.length;i++) {
18 s+= "<option value=\"" + values[i] + "\""
19 if(currentVal == values[i]) s+= " selected"
20 s+= ">" + labels[i] + "</option>"
21 }
22 s += "</select>"
23 //now replace
24 $(this).parent().html(s)
25 return false
26 })
27
28 })
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:
2
3 <head>
4 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
5 <script>
6
7 $(document).ready(function() {
8
9 //used for our drop downs
10 var values = [1,2,3,4]
11 var labels = ["Hated It","Disliked It","Liked It","Loved It"]
12
13 $(".changeable a.edit").click(function() {
14 //find the hidden item
15 var hiddenItem = $("input:hidden", $(this).parent())
16 //get the current val
17 var currentVal = hiddenItem.val()
18 //get the name
19 var currentName = hiddenItem.attr("name");
20 //now we can draw our drop down and select the right val
21 var s = "<select name=\""+currentName+"\">";
22 //hard coded values for our drop down
23 for(var i=0;i<values.length;i++) {
24 s+= "<option value=\"" + values[i] + "\""
25 if(currentVal == values[i]) s+= " selected"
26 s+= ">" + labels[i] + "</option>"
27 }
28 s += "</select>"
29 //now replace
30 $(this).parent().html(s)
31 return false
32 })
33
34 })
35
36 </script>
37 </head>
38
39 <body>
40
41 <form method="post">
42
43 star wars: <span class="changeable"><input type="hidden" name="starwars" value="4">Loved It - <a href="" class="edit">edit</a></span><br/>
44 star trek: <span class="changeable"><input type="hidden" name="startrek" value="3">Liked It - <a href="" class="edit">edit</a></span><br/>
45
46 <input type="submit" value="click me like you mean it">
47 </form>
48
49 <cfif not structIsEmpty(form)>
50 <cfdump var="#form#" label="form">
51 </cfif>
52
53 </body>
54 </html>


Comment 1 written by Gary Gilbert on 20 September 2009, at 12:57 AM
the struct dump returns the right results but your label never changes, is that a feature, or not the point of the excersise?
Comment 2 written by Raymond Camden on 20 September 2009, at 8:37 AM
Comment 3 written by Dan G. Switzer, II on 21 September 2009, at 5:55 AM
This has the benefit of being completely unobtrusive, but adds flexibility that a normally select box doesn't offer (such as the ability for the text to wrap lines.)
Also, on a note specific to your example, you might want to change the line:
$(this).parent().html(s)
To:
$(this).parent().html(s).find("select").focus();
So that the select element gets focus--which would improve keyboard usage quite a bit (since the select element would retain the focus that the anchor used to have.)
Comment 4 written by Raymond Camden on 21 September 2009, at 6:40 AM
Comment 5 written by Mike on 21 September 2009, at 10:27 AM
I realize there are 100 ways to do anything, and as a jQuery newb I am still trying to figure out if the way I accomplished something was a hack job or an elegant solution (it's not always easy to tell the two apart).
I had a similar situation for an "in-line edit", but went about it a little differently. In my form, instead of piecing together strings in JS to create the SELECT, I created the entire SELECT box (options and all) within the form in HTML, but gave it a class of 'hidden' (defined in CSS), thereby hiding it. When 'edit' was clicked, I simply removed the hidden class from the SELECT, and added the 'hidden' class to the 'edit' link.
Any comments, good and bad, about that solution?
Also, I'd love to see more real-world jQuery examples when dealing with dynamic/database driven data. Static examples are great, but nothing I build is static. I often question myself on how to deal with situations where both the jQuery code and the resultant HTML depend on dynamic data sets. I often result in looping over the data set twice, once for JS and the other for HTML, but I'm sure there are more elegant ways to pull ID's and values from the HTML in jQuery.
Comment 6 written by Raymond Camden on 21 September 2009, at 1:30 PM
Point taken on the dynamic part here - but I assume most readers would know how to dynamically output simple form values. I also like to focus on the item at hand and not distract people from the main point of the blog entry. Know what I mean?
Comment 7 written by keiron roberts on 16 March 2010, at 12:33 PM
Comment 8 written by Raymond Camden on 16 March 2010, at 5:08 PM
Comment 9 written by keiron roberts on 17 March 2010, at 3:19 AM
Your current script only accommodates select menus, but I made some changes yesterday to allow text and textarea too by looking at the class of the hidden field (that's all I need right now, but it could take any input). Plus it also gets the contents of the select menus from a php script to make each one unique and more dynamic:
$(".changeable a.edit").click(function() {
var hiddenItem = $("input:hidden", $(this).parent())
var currentVal = hiddenItem.val()
var currentName = hiddenItem.attr("name");
var currentType = hiddenItem.attr("class");
if(currentType == "textarea"){
var s = "<textarea name=\""+currentName+"\" >"+currentVal+"</textarea>";
}
else if(currentType == "select"){
var s = "<select name=\""+currentName+"\" id=\""+currentName+"\">";
s += "</select>";
$.post("select.php", {selectmenu: currentName, currentitem: currentVal},
function(data){
$(data).appendTo('#'+currentName);
});
}
else {
var s = "<input type=\"text\" name=\""+currentName+"\" value=\""+currentVal+"\" />";
}
$(this).parent().html(s);
return false
});
<input type="hidden" name="tacktype" value="Saddle" class="select" />
<input type="hidden" class="textarea" name="features" value="text here" />
Comment 10 written by Raymond Camden on 19 March 2010, at 1:14 PM
http://www.coldfusionjedi.com/index.cfm/2010/3/19/...
Comment 11 written by sadmin on 31 March 2010, at 6:37 AM
Who are facing? Can I use linkselect to submit a form?
Comment 12 written by sadmin on 31 March 2010, at 6:40 AM
Comment 13 written by Raymond Camden on 31 March 2010, at 8:35 AM
[Add Comment] [Subscribe to Comments]