The fastest easiest way to get it right.

Boston PHP 2009-03-11

This is the complete text of the presentation titled "jQuery and The Last Mile" given by Ken Downs to Boston PHP on March 11, 2009.


Tonight we will see how jQuery alowed us to complete the "Last Mile" of the x6 desktop-in-browser interface for the Andromeda Project, giving us workable auto-generated database maintenance screens and tools for custom screens.

jQuery allows for vastly improved productivity in browser programming. It touches nearly every subroutine in our Javascript library.

Links And Files

This page:

The demo we will see:

The Javascript Library:

PHP source code is available with these links:

What We Will See

  • jQuery's DOM manipulation is so powerful it is as if you could not do it at all before.
  • Cross-browser compatibility
  • Using effects consistently
  • Integration with a framework
  • Division of labor between jQuery and PHP
  • Division of labor between jQuery and vanilla javascript
  • Where jQuery does not or cannot solve a problem

About Andromeda and The Demo

The Demo program is an Andromeda application, this project exemplifies what Andromeda is all about.

  • Development Speed: The program as you see it took 75 minutes to develop, one 45 minute session and two additional 15 minute sessions.
  • Development Accuracy: Every tier of the application reflects the security and business rules of the application.
  • D-R-Y: The entire business rules, database structure, security, and default user interface parameters are in the database definition.
  • Automation: There are no program files in this application. The default "free" Andromeda admin interface never requires program files.
  • Customization: Even though this demo has no custom files yet, such things are part of all applications, and Andromeda expects them and fully supports them.
  • Keyboard Access: The application can be used in its entirety without ever touching the mouse (exceptions are considered bugs, please report them!)

The original version of Andromeda had no Ajax and no more than 50 lines of Javascript. When we wanted to go Ajax for a full desktop-in-browser experience, it was an absolute requirement that DOM manipulation be painless, that we be able to program at the speed of thought, which is nigh-on impossible with straight Javascript. P.S.: jQuery's effects were simply a bonus.

The Basics: Firebug

Tonight's presentation will make heavy use of Firebug, which fits hand-in-glove with jQuery.

Introduction To jQuery

Using Firebug and a demo screen, we will see all get on the same page on how to use jQuery commands.

Bring up the demo and go to customers screen.

  • Elements: $("div").css('backgroundColor','blue');
  • Elements by Class: $(".x6main").css('backgrounColor','red');
  • Elements by ID: $("#tc_customers").css('backgroundColor','green');
  • Elements by Type: $(":input").css('backgroundColor','yellow');
  • Getting Picky: $(":input:first").css('backgroundColor','cyan');
  • Isolating Searches: $("#grid_customers :input:first").css('backgroundColor','cyan');
  • Again: $("#ddisp_customers_inner :input:first").css('backgroundColor','purple');
  • Use your own attributes: $(":input[xcolumnid=description]").css('backgroundColor','purple');
  • Loops: $(":input").each( function() { console.log( } );

Some simple ideas that flow from jQuery's core function:

  • Idea 1: The basic ability to find items transforms horrifying javascript into elegant code that is easy to write, maintain, and improve.
  • Idea 2: jQuery's set-oriented approach reduces loop structures in favor of simple statements.
  • Idea 3:The ability to change items closes the loop on the basic reason why we code Javascript in the first place: DOM Manipulation.

Some Examples of DOM Manipulation

All of the examples of Javascript we will see are in the x6.js file referenced at the top of the page. To start out, we want to see some isolated examples of how jQuery is sprinkled throughout the program:

  • .val() Example: Go to Customers, type '*', hit Enter. Change Customer Name, then hit ESC. See line 5564, the value is replaced.
  • .html() Example, go to customer, type *, search results are returned. See line 5928, the prior search results are cleared before the search begins.
  • .replaceWith() Same example, see line 5946, the entire body is replaced when the HTML returns from the server.
  • Sidebar: events Same example as above, see next line, 5947, highlights first row by triggering mouseover event.
  • .attr Go to timeslips, detail, New line. Go to date and type in '031109'. See Line 3099, use of "attr()" to find value and reformat date.
  • .prepend() Log in as adminstrator user ad_003, go to project types. Hit the up arrow, a new row appears. See line 5211, the .prepend() function.
  • .append() Same example, hit down arrow until you scroll past bottom, a new row appears. See line 5215, the .append() function.

Comprehensive Example 1: Scrolling List

For this example, you must navigate to a page that is not on the menu. After logging in, go to this page: When the search grid comes up, hit '*', then hit PageDown a few times.

The code that supports this behavior begins at line 3987 of x6.js and is almost pure jQuery. Among the features we use are:

  • Find Highlighted Row using a class selector at line 4001.
  • Get the height of the line using .height() at line 4004.
  • Get the next row using .next() at line 4019.
  • Find out how many rows are above using .prevAll and .length at line 4021.
  • Scroll the body using .scrollTop as both getter and setter at lines 4023 and 4024.

Comprehensive Example 2: Auto-complete Fields

For this example, go to projects, detail, NEW. On the Project type field type '*'.

The entire behavior of the auto-complete field is controlled by an object x6inputs.x6select which is riddled through with jQuery. Some relevant lines when you hit '*' are:

  • We display the box using .css() setting at line 3752.
  • The titles are displayed with .html() at line 3808.
  • The first row is highlighed with .mouseover() at line 3855.
  • When you hit TAB, the correct value is found using a selector at line 3738.

Comprehensive Example 3: Modal Editing of Child Tables

For this exaple, go to Customers, type '*' and pick the first customer. Then click on the tab at the bottom "4: Projects", and click [NEW] inside the tab. A modal pops up that lets you create a project.

The sizing and placement of this modal are controlled by a routine of almost pure jQuery beginning at line 6569.

Note from Ken: This is the most recent feature I added to Andromeda as of this writing, and it is the most purely jQuery. I find the longer I use it, the more I use it for everything, it tends to crowd out all other techniques.

Some Consequences of jQuery's Power

Basic HTML habits become more important: id's for unique items, classes for non-unique.

Using your own custom attributes can give you lots of power in your Javascript code.

Debugging strategy, reduce your core logic to finding the jQuery selector, which you can manually tweak in Firebug before putting it into the code. See the example at line 3738 and line 3740.

When you've gone all the way, you end up with all DOM access through jQuery, all other logic in native Javascript.

The Obvious: Cross-Browser Compatibility

At this point it is worth bringing up cross-browser compatibility. The demo we are looking at works well in IE6, IE7, and Firefox.

jQuery could not do much for us in the way of CSS incompatibilities, that was our own nightmare we had to solve.

In very late drafts of x6.js Ken was still using code that treated the "value" attribute of inputs as if it were a property. This works fine in Firefox, but broke completely in IE. Switching over to .val() solved that entire problem nicely.

Comprehensive Example 4: Fade and the Menu

The menu page (not the top menu) makes use of the fade effect and custom attributes. Most of the code is in x6menu.php.

When a user clicks on a module on the left side, the code at line 128 turns off keyboard responses to the right side just before beginning the fade.

At line 136 the fadeOut() of the old module begins, an then simultaneously at line 142 the new module begins fading in. Only when the new module is faded in do we activate keystroke responses again at line 144.

This example also illustrates the use of Custom Attributes to control behavior. We respond to letter keystrokes by finding a menu entry with the attribute 'xkey' that equals the letter. But how do we keep straight the sub-menus for all of the modules? We add another attribute 'xActive', which is only set to 'Y' for the active submenu. Line 210 shows the code that receives the keystroke and picks the menu entry to select. The fact that jQuery returns an empty set w/o error is a big help here.

PHP and $(document).ready()

jQuery has a nice feature, the $(document).ready() function which lets you add code that is executed when the page has loaded.

Since much of our HTML is generated by PHP, it stands to reason that the commands we put in here will vary according to what HTML we have generated.

This is our first example of a case where we need PHP to generate jQuery-specific items. One very flexible way to do this is to make up a function like 'jqDocReady()' which accepts a string fragment for later output to the browser. Our own function is at line 11235 of androLib.php

Some type of routine must then spit this all out, so our own code for this is at the bottom of androHTMLFoot.php, beginning at line 90.

Division of Labor jQuery and PHP

Idea 1: PHP exists to generate HTML, so keep it that way, just because jQuery (and other libraries) can render HTML easily, does not mean they do it quickly.

As an example, view the source of the customers page, it contains the entire HTML for anything that might be visible at any time. It is all generated by PHP, jQuery is only used to manipulate it.

Idea 2: jQuery (and Javascript generally) can be put to best use manipulating the DOM, this is all that is left if the HTML still originates from the server.

Things jQuery Cannot Overcome

All jQuery plugins are not created equal, and they are not always compatible. But we've all found this out the hard way, right?

All events are not created equal, if you want to capture arrow keys it is the keyDown event in IE, but keyPress in Firefox. See Line 530 of x6.js.

Unless I am completely missing something, jQuery does not provide a uniform way to prevent event propagation/bubbling, so I had to write my own, see line 60 of x6.js.

comments powered by Disqus
Home |  Documentation |  Download |  Credits |  Contact |  Login
Andromeda © Copyright 2004-2013, Licensed under the GPL Version 2