This weekend I wrote up a quick blog post that demonstrated using jQuery and jQuery UI for front end editing of database content. ColdFusion was used to store changes made via a jQuery dialog and jQuery did all the handling of data back and forth. Alex asked if it was possible to demonstrate the code using a table instead of the lovely green divs I had created. Here is what I came up with. I'm going to focus on the changes so please be sure to read the previous entry for details on how this all works together. Ok, so first, the template.
<html>
<head>
<script src="jquery-ui-1.8.7.custom/js/jquery-1.4.4.min.js"></script>
<script src="jquery-ui-1.8.7.custom/js/jquery-ui-1.8.7.custom.min.js"></script>
<link rel="stylesheet" href="jquery-ui-1.8.7.custom/css/overcast/jquery-ui-1.8.7.custom.css" />
<script>
//credit: http://www.mredkj.com/javascript/numberFormat.html
function dollarFormat(nStr){
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return "$" + x1 + x2;
} $(document).ready(function() { $(".editLink").click(function(e) {
var initialRow = $(this).parent().parent(); //based on which we click, get the current values
var artid = $(initialRow).data("artid");
var name = $("td:first", initialRow).text();
var price = $("td:nth-child(2)", initialRow).data("price");
console.log(price);
var desc = $("td:nth-child(3)", initialRow).text();
desc = $.trim(desc); $("#artid").val(artid);
$("#namefield").val(name);
$("#pricefield").val(price);
$("#descriptionfield").val(desc); $("#editForm").dialog({
buttons: {
"Save": function() {
var thisDialog = $(this);
$.post("artservice.cfc?method=saveart",
{
id:$("#artid").val(),
name:$("#namefield").val(),
price:$("#pricefield").val(),
description:$("#descriptionfield").val()
},
function() {
//update the initial div
$("td:first", initialRow).text($("#namefield").val());
var price = $("#pricefield").val();
$("td:nth-child(2)", initialRow).data("price", price);
price = parseInt(price).toFixed(2);
$("td:nth-child(2)", initialRow).text("Price: "+dollarFormat(price));
$("td:nth-child(3)", initialRow).text($("#descriptionfield").val());
$(thisDialog).dialog("close");
});
}
}
}); e.preventDefault();
}); });
</script>
<style>
.artdiv {
padding: 5px;
margin: 5px;
background-color: #80ff80;
}
#editForm {
display:none;
}
</style>
</head> <body> <table width="100%" border="1">
<tr>
<th>Name</th>
<th>Price</th>
<th>Description</th>
<th> </th>
</tr> <cfoutput query="getart"> <tr data-artid="#artid#">
<td>#artname#</td>
<td data-price="#price#">
Price: #dollarFormat(price)#
</td>
<td class="description">
#description#
</td>
<td><a class="editLink" href="">Edit</a></td>
</tr> </cfoutput> </table> <div id="editForm" title="Edit Art">
<input type="hidden" id="artid">
<p>
<b>Name:</b><br/>
<input type="text" id="namefield">
</p>
<p>
<b>Price:</b><br/>
<input type="text" id="pricefield">
</p>
<p>
<b>Description:</b><br/>
<textarea id="descriptionfield"></textarea>
</p> </div> </body>
</html>
<cfset getArt = new artservice().getArt()>
So the first obvious change is the display at the bottom. Instead of a list of DIVs I output table rows. That's a pretty simple change. I also added an edit link as the fourth column in the table.
Now go back up to the document ready block. I'm now listening for clicks to my new edit link. Note that at the very end I now use e.preventDefault() to block the browser from actually trying to do something with the link. The only other change then is to how I get the various values. Notice I get the table row by using parent.parent on my link. Once I have that, I use a combination of td:first and td:nth-child calls to get at my various items. Outside of that though nothing much else has changed. If you want to run this, please download the attachment from the previous entry and just copy the code above into a new table. Hope this helps!
Archived Comments
The jQuery .data method is new to me. Thanks for pointing that one out.
I think data-artid, and data-price are red herrings.
Are they?
Oh, I see. It has to do with HTML5.
http://ejohn.org/blog/html-...
HTML5 allows you to specify data-ANYTHING="foo" in tags. It's ignored by the rendering engine but shows up in your DOM. jQuery then provides an easy way to set/get them.
Nice post as always Ray. The only issue I see is the dollarFormat function you borrowed from mredkj.com. That function makes use of un-var'd variables, and thus will place them in the global window object. This code demonstrates the problem.
<script type="text/javascript">
var x = 15;
function dollarFormat(nStr){
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return "$" + x1 + x2;
}
function improvedDollarFormat(nStr){
nStr += '';
var x = nStr.split('.');
var x1 = x[0];
var x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return "$" + x1 + x2;
}
alert("x = " + x);
alert(dollarFormat("444.55"));
alert("x = " + x);
/* Reset test */
x = 15;
alert("x = " + x);
alert(improvedDollarFormat("444.56"));
alert("x = " + x);
</script>
Ah good catch there. Thanks.
Sorry for the noob question but...
How do you go about 'adding/deleting' and refreshing the table?
On your form, how do you handle dealing with dropdowns, checkboxes and radio buttons?
I think that's what's missing to this lovely example.
Any help/tip would be greatly appreciated.
Thanks,
RD
Deleting could be a simple link in each row that passes the ID of the row to delete.
For add, you would pop up the dialog but not preload any of the form values. You would want to set the ID to something like 0 or keep it blank, and ensure "saveavrt" can handle that.
As for the dropdowns and checkboxes, well, the API for them is just a bit more complex. Enough for me not to want to write the code in a comment box. ;) For a checkbox, it's a matter of getting them all and finding the one with the right value to check. jQuery makes that easy. For a select box it's simiilar.
Hi Ray
How can I expand the code so once the save button is clicked update the initial page as well. DO I just need to reload a page
If you just want to reload an entire page you can use window.location.href=.... Or use window.location.reload.
and if we just ned to reload the DIV after the initial Add or Edit, Then what we need to do!
Not quite sure I get you Misty, but reloading content in a div is easy with JS, even easier with jQuery.
Its just like this,
1. Opened the dialog,
2. I added a new Entry
3. I clicked Add
4. Add will add the entry & close the dialog Box,
5. I have wrapped the table with a DIV id="refreshDiv">
6. Question, How on Closure of the Dialog when i Press Add will trigger the <DIV> which refreshes it and show the added record.
I have implemented Add/Delete Functionality & i will share it with you asap!, Once i Complete this
Whatever you use to close the dialog (a link for example) should use an event handler to do the rest of your process.
what exactly are u trying to say, dialog box just closes the dialog and doesnot refresh the div, i can add the tr td manually but that is not what i m trying
What do you mean when you say dialog box exactly? If it is a jQuery UI dialog, you have the option to do something on close.
I think I just learned yesterday that $(this).data('ANYTHING') is different from the data-ANYTHING attribute. For example, if you have data-ANYTHING and you say removeData('ANYTHING'), it's not going to work - you have to use removeattr('ANYTHING').
removeAttr('data-ANYTHING')
Interesting. If I had to guess, I'd say $(this).data is a polyfill for things that don't support data-*. I'm not sure though. I'd check the docs.
I don't know - it seems like it should be the same in any modern jQuery lib: http://api.jquery.com/data/...
OK, I've put together a proof-of-concept.
http://www.phillipsenn.com/...
Doing a bit of research and found this: http://www.visualjquery.net...
Note specifically this portion: (btw, api.jquery.com is down for me so I can't find the official doc) "NOTE: Starting with jQuery 1.4.3, calling .removeData() will cause the value of the property being removed to revert to the value of the data attribute of the same name in the DOM, rather than being set to undefined."
This seems to mesh with your demo where removeAttr just reverted it back to the DOM value.