Saturday, August 30, 2008

Momentary Hiatus

I've taken a couple of days off to see my latest book into print. If you're a ColdFusion developer, take a look at "How to Drive Fusebox 5.5", available at Proton Arts.

And, to keep things on the jQuery front alive, here's a great project from Michael Sprague: CFjqAJAX, a library of jQuery tools designed to replace CFGRID, CFWINDOW and CFTOOLTIP in ColdFusion 8. (Thanks to Sean Corfield for the heads-up).

Wednesday, August 27, 2008

A Popup Form Deconstructed

Looking at the JavaScript code from "A Popup Form", there are really only two things going on in this function. The first is that we build this huge string named s. The second thing is that we inject that HTML into the document using jQuery:

$("body").append(s);

This causes the form to pop up. But the fun stuff is really happening within that HTML string named s. So let's take a look at its parts and see what they do.

First thing to mention is that this piece of code breaks one of my favorite best practices--keeping content (HTML), display (CSS) and behavior (JavaScript) in distinct files. It's a trade-off. The idea behind this example is that we have a very small form that we might want to use in several places in the application. By having it all included in a single JavaScript file, we can easily leverage it wherever we want. Anyway, back to the code.

There are three sections of code inside s: the CSS, the HTML, and the JavaScript. We'll look at each individually, starting with the CSS.


<style>
#formDiv {
position: absolute;
top: 100px;
left: 100px;
background-color: #D9E8D7;
color: #33532F;
border: 1px solid #33532F;
padding: 12px 6px 0px 6px;
font-family: Tahoma, Helvetica, sans-serif;
font-size: 9pt;
text-align: center;
}
</style>
This is just plain old CSS to position, size, and color the popup the way we want it. One important thing to note is the use of position: absolute. Since this div is being injected a the end of the content of the body element, it's reasonably safe to position it absolutely (i.e., from the body element's upper left corner).

The we have the HTML section of the code:

<div id="formDiv">
<strong>New Employee</strong><br /><br />
<form name="newEmployeeForm" id="newEmployeeForm" method="post">
First Name: <input id="firstName" name="firstName" type="text" /><br />
Last Name: <input id="lastName" name="lastName" type="text" /><br />
<input type="submit" name="btnSave" id="btnSave" value="Save">
<input type="button" name="btnCancel" id="btnCancel" value="Cancel">
</form>
</div>
Again, nothing fancy here--just basic HTML to display the popup's title, text inputs for firstName and lastName, and buttons for Save and Cancel. Notice, though, the use of id attributes for all the inputs and the popup's div. These are critical for the next part--the JavaScript.

<script type="text/javascript">
formInfo = "";
We start by setting the formInfo variable to an empty string. This just makes sure we're not carrying around extra information by chance.


$("#btnCancel").click(function(){
returnResponse("Cancelled");
});

Now we set the button whose id is btnCancel to call the returnResponse() function when clicked. It includes the string "Cancelled" as an argument to the function.

$("#newEmployeeForm").submit(function(){
formInfo = new Object;
formInfo.firstName = $("#firstName").val();
formInfo.lastName = $("#lastName").val();
returnResponse(formInfo);
});

Now we assign some behavior to the form itself (id is newEmployeeForm). When the form is submitted, we create a new Object and save it with the name formInfo. Then we fetch the values from the firstName and lastName fields and store them to properties of the formInfo object. Notice we're taking advantage of id attributes again--one of jQuery's strong suits. Finally, we call the returnResponse() function, this time with the variable formInfo as its argument.

function returnResponse(fI){
$("#formDiv").remove();
' + callbackFunc + '(fI);
}
</script>
The last part is the definition for that returnResponse() function. All it does is remove the formDiv (the popup) from the DOM, and then do something with a variable called callbackFunc. Let's take a closer look at that.

Remember this is all in the context of building that string variable called s. So that line with the callbackFunc variable is really building some text that uses a value stored in the callbackFunc variable. Looking back at the top of the code, the function signature for showPopup() specifies an argument called callbackFunc:
function showPopup(callbackFunc) {
This is where we get that value. In the calling page, the showPopup() function is called with an argument of 'processData'. So the script is actually building a line that looks like this:

processData(fI);

This is how the script triggers the callback function. Of course, the fI variable is just passing along what was passed into the returnResponse function--either the string "Cancelled" in one case, or the object formInfo in the other.

That's it. The callback function can now deal with the response data in any way it wants. In this example, we're just plugging the values into a string and displaying an alert box to show how it works. In an application, we might be doing something like plugging the new values into a list, etc.

Have fun!

Tuesday, August 26, 2008

A Popup Form

Today's tidbit is a way to inject a popup form into a page and use its form fields on the page once the form has been submitted. Of course, once submitted, the form should destroy itself. These pics show the sequence of events:

1. The initial page with just a button



2. Click the button and the form pops up:



3. Fill out the form:



4. Click Save and the form data returns to the page. Here we're just using an alert() to show that the data made the trip back to the controlling page:



This technique can be used for all kinds of small popup forms. You could create your own message popup that looks nicer than the alert() box, for example.

Here's the calling page for the example, which just fetches a new employee's first and last names:
<html>
<head>
<title>Popup Form Test</title>
<script type="text/javascript" src="../../jquery/jquery.js"></script>
<script type="text/javascript" src="popupFormFunction.js"></script>
<script type="text/javascript">
function processData(formData){
s = formData != "Cancelled" ? formData.firstName + ' ' + formData.lastName : formData;
alert(s);
}
</script>
</head>
<body>
<input type="button" id="btnShowForm" value="New Employee" onclick="showPopup('processData');" />
</body>
</html>

All this page does is show a button. When you click the button, it pops up the form using the showPopup() function. When the form is submitted, it runs the callback function specified in the showPopup() argument--in this case that function is processData().

Here's the content of the popupFormFunction.js file:

function showPopup(callbackFunc) {
s = '';
s += '<style>';
s += ' #formDiv {';
s += ' position: absolute;';
s += ' top: 100px;';
s += ' left: 100px;';
s += ' background-color: #D9E8D7;';
s += ' color: #33532F;';
s += ' border: 1px solid #33532F;';
s += ' padding: 12px 6px 0px 6px;';
s += ' font-family: Tahoma, Helvetica, sans-serif;';
s += ' font-size: 9pt; ';
s += ' text-align: center; ';
s += ' }';
s += '</style>';
s += '';
s += '<div id="formDiv">';
s += ' <strong>New Employee</strong><br /><br />';
s += ' <form name="newEmployeeForm" id="newEmployeeForm" method="post">';
s += ' First Name: <input id="firstName" name="firstName" type="text" /><br />';
s += ' Last Name: <input id="lastName" name="lastName" type="text" /><br />';
s += ' <input type="submit" name="btnSave" id="btnSave" value="Save"><input type="button" name="btnCancel" id="btnCancel" value="Cancel">';
s += ' </form>';
s += '</div>';
s += '';
s += '<script type="text/javascript">';
s += ' formInfo = "";';
s += ' $("#btnCancel").click(function(){';
s += ' returnResponse("Cancelled");';
s += ' });';
s += ' $("#newEmployeeForm").submit(function(){';
s += ' formInfo = new Object;';
s += ' formInfo.firstName = $("#firstName").val();';
s += ' formInfo.lastName = $("#lastName").val();';
s += ' returnResponse(formInfo);';
s += ' });';
s += ' function returnResponse(fI){';
s += ' $("#formDiv").remove();';
s += ' ' + callbackFunc + '(fI);';
s += ' }';
s += '</script>';
$("body").append(s);
}


I put the HTML, CSS, and JavaScript for the form all into a string variable, then inject that HTML into the DOM. This can be done in any of a variety of ways--that stuff could be an HTML file that we fetch via HTTPRequest, for example. The way I have it here is just a nice concise way to represent the technique.

Deconstruction to follow tomorrow--there are lots of fun little techniques to be mined from this example.

Monday, August 25, 2008

Totaling Table Columns Deconstructed

So the last post provided a function that calculates totals based on classes placed on rows in a table. This post will go through that function line-by-line so all its secrets are revealed. If you're already a jQuery pro, you can skip these "Deconstructed" posts, as they're really aimed at a detailed understanding of the code.

Now, before we even start, there's a piece of code that's not mentioned. It's the call to the jQuery library, without which all is for naught. It should look like this:

<script type="text/javascript" src="../js/jquery.js"></script>

The part that will change on your local file is the src attribute. The value there needs to be whatever the path is to your local jQuery library. With that in place, we're ready to move on. Let's get to it.

function totalTableSubRows(tableID, totalClass, dataClass, columnNumber) {

The first line of the function is its signature. It specifies that the function takes four arguments. They are:
tableID: the HTML id of the table to use
totalClass: the CSS class of the row where totals should be placed
dataClass: the CSS class of rows where data is located
columnNumber: the column number (left to right, starting at 1) where the data is located

Now we get into the meat of the thing. First, some variables are set:

tableSelector = "#" + tableID;
totalSelector = "." + totalClass;
dataSelector = "." + dataClass;
columnIndex = columnNumber - 1;

The first three assignments take the arguments passed into the function and turn them into the selector strings we're going to need in order to work with jQuery. The hash (#) is the symbol for matching an HTML id attribute, so it gets prepended to the tableID. The dot (.) is the symbol for matching an HTML class attribute, so it gets prepended to the class names for the totals row and the data rows.

The fourth assignment adjusts the column number so that it uses JavaScript-friendly zero-based indexing, instead of the more human-friendly 1-based indexing. That is, when we count the columns in the table, we naturally start with 1 at the leftmost column, and count to the right. So we would say the second column's index is 2. But JavaScript calls the first thing 0, so the second column would be 1, and so forth. Subtracting 1 from the argument allows us to use human-friendly counting, while the function uses JavaScript-friendly counting. Everybody's happy.

$(tableSelector + ' tr' + totalSelector).each(function(){

Now starts the jQuery. The $ symbol is an abbreviation for "the jQuery object". So $() is the same as saying jQuery(). We'll be seeing this a lot.

jQuery's argument is called a selector. The selector causes jQuery to return a JavaScript object of type jQuery which contains every element in the DOM that matches the selector. jQuery methods can then act on the members of this return set.

The first selector combines the tableSelector and totalSelector variables, separated by space-tr-space. Since the tableSelector specifies the table's ID, and the totalSelector specifies the class of the totals row(s), this combination says, "select all td elements with a class equal to the value of totalSelector that are descendants of the element whose ID is equal to the value of tableSelector".

The .each() method says "do what's inside my parens for each member of the selected jQuery object." So what's inside its parens? Turns out, a good bit.

In JavaScript, "function" is a first-class datatype. That just means that we can specify a function as a set of instrutions that can then be passed around assigned by its name. If we don't need to use a name, we can use the so-called "anonymous function" construct, as seen here. Notice there's no function name after the keyword function. We're just creating a function on the fly and handing it as an argument to the each() method. By doing this, we've assigned behavior that will be performed for each member of the return set (in this case, all the total rows).

$(this).children("td:eq(" + columnIndex + ")").html(0);

Now we have another jQuery selector. This one is based on the this keyword. Note that it is not within quotes. To jQuery, this means "the element referred to by each() at this time". In this case it means "this total row".

The children() method means "look for the selector in my argument in the elements that are direct children of the return set". At this point, the return set is a single row of the table (specified by $(this)). The selector passed to it uses the :eq() filter to find a specific td element. In this case, it's finding the cell specified by the columnIndex variable.

The next part of the line shows an example of jQuery chaining. Every jQuery method returns the same return set for which it is a method. This means that methods can be strung together in a chain, with each method operating in turn on the return set. This is the case with the html() method at the end of this line. It's simply setting the HTML inside the selected td element to 0.

So this line is simply saying "Set all the td's in the specified column of each total row to 0."

total = 0;

Now we initialize the total variable to zero.

$(this).nextAll().each(function(){

And use another jQuery selector. Again, we're using this to operate on each total row (we're still inside the function for the each() method that selected total rows, remember). The nextAll() method says "select all sibling elements that come after the specified element". And each() once again allows us to assign behavior to each of those siblings.

if($(this).hasClass(dataClass)){

Now some conditional logic: if the selected element (row, in this case) has the value specified by dataClass as its class attribute, we'll do the next four lines.

thisVal = $(this).children("td:eq(" + columnIndex + ")").html() * 1;
if (!isNaN(thisVal)) {
total += thisVal;
}

The first line pulls the value out of the specified cell (td) and makes sure JavaScript will treat the number as a value by multiplying it by 1. If that multiplication doesn't result in "NaN" (i.e. the cell contained a number), that number is added to the total.

If the row doesn't have the dataClass assigned as its class, then we'll do the next rows:

} else {
if($(this).hasClass(totalClass)){
return false;
}
}

We don't want to do anything, unless run across a row that has the class specified in the totalClass variable. In that case, we want to quit adding values to the total, because we're done with the children of the current total row. This is what the return false statement does.

And this is the end of the function definition inside the each() after the nextAll():

});


$(this).children("td:eq(" + columnIndex + ")").html(total);

Now we're back in the each() function of the original selector (the total row), so we just select the child td element in the desired column (:eq() with the columnIndex variable) and assign the calculated total as its HTML content (html()).

This is a good place to point out the dual nature of many jQuery methods. These methods at as both "getters" and "setters". If no argument is given, the method returns the requested value. If an argument is specified, the method sets the specified value. So, in this example, we've used the html() function to both set the value and fetch the value of some td elements.

});
}

Finally, we're just closing out the function that's inside the each() method, the each() method itself, and the totalTableSubRows function.

To call this function, we just need to specify the desired arguments. As we saw in the previous post, those calls look like this:

totalTableSubRows("myTable","regionRow", "storeRow",2);
totalTableSubRows("myTable","totalsRow", "storeRow",2);

The first one says, "Put the totals of storeRows' second columns in their respective regionRows".
The next one says,
"Put the totals of storeRows' second columns in their respective totalsRows".

Happy jQuerying!

Totaling Table Columns

Many of the applications I deal with are financial in nature, and often have a requirement to provide subtotals and totals of column rows. This can be a daunting exercise if attacked from a DOM perspective, but it's pretty easy with jQuery. Take a look at this table:














We want to be able to total the stores' sales figures for each region, then provide a grand total up a the top. To make this easy, I assigned an ID to the table, and a class to reach row depending on its type. Here's the table code:


<table id="myTable" border="1">
<thead>
<tr class="headerRow">
<th>Region</th>
<th>Sales</th>
</tr>
</thead>
<tbody>
<tr class="totalsRow">
<td>All</td>
<td>0</td>
</tr>
<tr class="regionRow">
<td>North</td>
<td>0</td>
</tr>
<tr class="storeRow">
<td> Boston</td>
<td>10</td>
</tr>
<tr class="storeRow">
<td> New York</td>
<td>20</td>
</tr>
<tr class="regionRow">
<td>South</td>
<td>0</td>
</tr>
<tr class="storeRow">
<td> Charleston</td>
<td>40</td>
</tr>
<tr class="storeRow">
<td> Atlanta</td>
<td>80</td>
</tr>
</tbody>
</table>


You can see the classes defined for totalsRow, regionRow, and storeRow. Now all we need is a little plumbing to figure out the totals. Here's a function I wrote that will work with any table having figures in columns (that is, no additional markup inside the tags):


<script type="text/javascript">
/*
totalTableSubRows()
By Jeff Peters, Aug 2008. Released to the public domain.
Courtesy of jQuery Nuts and Bolts, http:// jquerynab.blogspot.com
*/
function totalTableSubRows(tableID, totalClass, dataClass, columnNumber) {
tableSelector = "#" + tableID;
totalSelector = "." + totalClass;
dataSelector = "." + dataClass;
columnIndex = columnNumber - 1;
$(tableSelector + ' tr' + totalSelector).each(function(){
$(this).children("td:eq(" + columnIndex + ")").html(0);
total = 0;
$(this).nextAll().each(function(){
if($(this).hasClass(dataClass)){
thisVal = $(this).children("td:eq(" + columnIndex + ")").html() * 1;
if (!isNaN(thisVal)) {
total += thisVal;
}
} else {
if($(this).hasClass(totalClass)){
return false;
}
}
})
$(this).children("td:eq(" + columnIndex + ")").html(total);
})
}

$(document).ready(function(){
$("#btnCalculate").click(function(){
totalTableSubRows("myTable","regionRow", "storeRow",2);
totalTableSubRows("myTable","totalsRow", "storeRow",2);
});
});
</script>


To make it work , you just call it with the desired parameters. Since we want to sets of calculations--one for the region rows, and one for the totals row, we call the function twice:

totalTableSubRows("myTable","regionRow", "storeRow",2);
totalTableSubRows("myTable","totalsRow", "storeRow",2);

The first call goes to myTable, calculates the totals from the storeRow rows under each regionRow row, and returns the total for each regionRow row to that row, with numbers found in the second column. The second call does the same thing, but totals all regionRow rows under the totalsRow. All done.

This function is extremely useful if you're injecting rows of data into the table. You can run the function right after a row injection (or deletion), and see the totals stay current.

As soon as I can figure out how to get blogspot to allow demo code pages, I'll post this so you can watch a live demo here.

First Things First

Oh, no! Not another blog! More junk to follow, etc., etc.

That's how I figured you, the audience, might see this little effort. But I hope to make this blog a little bit different by putting first things first.

When it comes to developing web apps, the user experience comes first. After all, if the user doesn't like it, it won't be used--so much for the greatest web app in history.

In similar fashion, when it comes to blogs about programming, I think what matters is *what* the thing does--how it does it is really secondary (though often very valuable) information.

So that's what I intend to do: offer examples of jQuery in action, then take apart the code to see what's under the hood. The first part should appeal to you if you just want a new widget to add to an app; the second part is for those who want to explore jQuery more than they've had a chance to yet.

So that's it. Please feel free to drop comments, tell your friends, ask questions, and generally be part of the "thing". We're all friends here.