Bristle Software JavaScript Tips

This page is offered as a service of Bristle Software, Inc.  New tips are sent to an associated mailing list when they are posted here.  Please send comments, corrections, any tips you'd like to contribute, or requests to be added to the mailing list, to tips@bristle.com.

Table of Contents:

  1. Getting Started
    1. JavaScript Intro
    2. Popup Messages
    3. JavaScript Variables
    4. HTML Syntax
      1. HTML <script> Tag
        1. HTML <script> Tag With Inline JavaScript Code
        2. HTML <script> Tag To Load a Separate JavaScript File
    5. JavaScript Namespaces
      1. Creating a namespace
  2. DHTML
    1. DHTML Intro
    2. Getting an HTML element to operate on
    3. Name vs. Id
    4. Getting dynamic style of an HTML element
    5. Hiding/showing HTML elements
    6. Enabling/disabling HTML elements
    7. Bolding/unbolding HTML text
    8. Setting color
  3. DOM Events
    1. Handling Events
      1. Handling Events via HTML Attributes
      2. Handling Events via DOM Properties
    2. Getting the Event keyCode
  4. Controlling the Browser
    1. Disabling the Backspace key
    2. Showing a temporary statusbar message
  5. Ajax
    1. Ajax Intro
      1. What is Ajax?
      2. Why use Ajax?
      3. How Much to use Ajax?
      4. See Also
    2. Simple Ajax Example
    3. XMLHttpRequest Methods
    4. XMLHttpRequest Properties
    5. Bristle Ajax Library
      1. Create an Ajax Object
      2. Register Ajax Callbacks
      3. Get XML via Ajax
      4. Synchronous Ajax
    6. Loading Images
      1. Set the SRC property of the IMG
      2. Prevent Browser Image Caching
      3. Beware <IMG SRC=''>
    7. Using Ajax for a Keep-Alive
    8. Using Ajax for Drill-down (Coming soon...)
    9. Using Ajax for Infinite Scrolling of Long Tables (Coming soon...)
    10. Using Ajax for Data Validation (Coming soon...)
    11. Comet: Using Ajax for Server Push (Coming soon...)
  6. Algorithms
    1. Generating random numbers (coming soon...)
    2. Generating unique variable names (coming soon...)
  7. Tools
    1. Debugging Tools
      1. View Source
      2. View Source of Referenced JavaScript and CSS Files
      3. Firefox View Live Source
      4. Firefox DOM Inspector (coming soon...)
      5. Firefox Developer Kit (coming soon...)
      6. Venkman JavaScript Debugger (coming soon...)
      7. Firebug JavaScript Debugger (coming soon...)
      8. Microsoft Script Debugger (coming soon...)
  8. See Also

Details of Tips:

  1. Getting Started

    1. JavaScript Intro

      Original Version: 4/14/2007
      Last Updated: 4/30/2007
      Applies to:  JavaScript 1.0+

      JavaScript (more properly called ECMAScript) is not Java.  However, for their simpler features, they both use the same syntax as C, C++, Perl and many other languages, all based originally on the syntax of the C language.  For many of the basic programming constructs, it is hard to tell which language you are looking at:

              // One-line comment
              /* Block comment */
              if (x==y) {doSomething(); } else { doSomethingElse(); }
              for (i=1; i < 10; i++) { doSomething(); } 
              while (i < 10) { doSomething(); }

      However, the similarities end there.  Java is a "strongly typed" and "statically typed" language where the compiler catches many simple programmer mistakes by requiring an object to be declared with a data type and to maintain that same data type at all times.  It is very good for writing large scale mission-critical systems.  JavaScript is a "dynamically typed" scripting language where you don't declare the type of an object, and its type can change on the fly.  You can even add new properties and methods to an object on the fly.  Very good for writing small scale non-critical bells and whistles to run in a Web page, as part of the user interface to a Java application.

      You don't need to download and install a compiler or runtime environment for JavaScript.  There is a JavaScript interpreter built into every Web browser.  Therefore, JavaScript is commonly used for logic written to run in the browser for a Web application, including the browser-side logic for "AJAX" interactions (more on that later).

      For more details, see the JavaScript and ECMAScript links on my links page:

          http://bristle.com/~fred/#javascript

      --Fred

    2. Popup Messages

      Last Updated: 4/17/2007
      Applies to:  JavaScript 1.0+

      The simplest way to prompt the user in JavaScript is to pop up a message and wait for the user's response.  There are 3 standard JavaScript methods to do so: 

      alert (message) Pop up a message with an OK button.  Wait for OK to be clicked.
      confirm (message) Pop up a message with OK and Cancel buttons.  Wait for a button to be clicked.  Return true if OK is clicked; false if Cancel.
      prompt (message, [default]) Pop up a message and a text input field with OK and Cancel buttons.  If a default value was specified, initialize the input field with it.  Otherwise, leave the input field empty.  Wait for the user to optionally change the value of the input field, and then click a button.  Return the value of the input field if OK is clicked; null if Cancel.

      These are the simplest ways to prompt the user.  However, they have a number of limitations:

      1. They do not support HTML messages.
        The message string must be a simple JavaScript string of text.  HTML elements are not rendered, so you cannot specify fonts, colors, sizes, styles, background color, images, tables, etc.  However, you CAN embed newline chars in the string as:  "line 1\nline2\nline3", except for the Internet Explorer version of prompt() which chops it off at the 2nd newline.
         
      2. They are synchronous.
        The next line of JavaScript does not execute until the user clicks OK or Cancel.  Therefore the entire thread is held up waiting for a response.
         
      3. They are modal.
        The user cannot ignore the popup and continue interacting with the window under it.  He must respond to the popup first.  Therefore the entire window, and perhaps the entire application is locked until he responds.
         
      4. They are not copyable.
        The user cannot copy and paste the message into a document, a support log, or a mail message to report the error to a support team
         
      5. They require dismissal.
        The messages do not go away if the user ignores them or moves the mouse away.  They must be explicitly dismissed by clicking a button (or by hitting Enter for OK or Esc for Cancel).  Also, you cannot write JavaScript code to dismiss them automatically (after a timeout, or after some user action, for example).
         
      6. They are not scrollable
        The message string is displayed without a scrollbar, so long messages fall off the bottom of the screen.  Furthermore, since the buttons appear below the text of the message, long messages push the buttons off the bottom of the screen so the user cannot dismiss the message with the mouse and has to use the Enter or Esc key.
         
      7. They are immutable
        The message string cannot be changed, or more messages appended to the same popup, after the popup has occurred.  Sometimes it is useful to have a single popup that shows a series of messages, with more messages being added as the user reviews earlier messages.
         
      8. They may interfere with other events.
        Because of the "nested modal event loop" used to implement these methods, you may find that they interfere with other events.  For example, a timer event may be lost while the popup is waiting for a user response.  Or an asynchronous AJAX event may be lost.

      These are good for debugging (other than issue #8 above, which can be a problem when trying to track down a bug), and for demos, but not so good for production code, where it is often better to pop up a message that is HTML, asynchronous, non-modal, copyable, able to be dismissed programmatically, scrollable, changeable, and doesn't interfere with other events.  In a future tip, I'll describe how.  

      Meanwhile, for a transient message that does not require dismissal, you may prefer to use the "title" attribute of an HTML element instead.  It appears automatically when the user hovers the mouse over the HTML element and disappears automatically when the user moves the mouse or hits a key.  Or write JavaScript code to respond to events like onmouseover, onmouseout, onkeyup, etc.

      For more info on alert(), confirm(), prompt() and other standard JavaScript functions, see:

          http://www.javascriptkit.com/jsref/globalfunctions.shtml

      --Fred

    3. JavaScript Variables

      Original Version: 4/14/2007
      Last Updated: 5/4/2007
      Applies to:  JavaScript 1.0+

      As in most scripting languages, JavaScript variables are dynamically typed.  When you declare a variable, you don't give it a static type.  Instead, you simply declare it and/or initialize it.  You must do one or both of these before referring to its value.  Thus:

              var x = 1;      // Declares x with a numeric value of 1.
              alert(x);       // Shows:  1
      
              y = "hello";    // Initializes (and implicitly declares) y 
                              // with a string value of "hello".
              alert(y);       // Shows:  hello
      
              var z;          // Declares z with a special undefined value.
              alert(z);       // Shows:  undefined
      
              z = y + y;      // Assigns z the string value "hellohello".
              alert(z);       // Shows:  hellohello
      
              z = x + x;      // Assigns z the numeric value 2.
              alert(z);       // Shows:  2
      
              x = "a string"; // Assigns x the string value "a string", 
                              // changing its type from numeric to string.
              alert(x);       // Shows:  a string
      
              z = x + x;      // Assigns z the string value "a stringa string"
              alert(z);       // Shows:  a stringa string
      
              var z;          // Re-declares z, leaving its value intact.
              alert(z);       // Shows:  hellohello
      
              alert(zz);      // Throws an exception, since zz does not exist.

      --Fred

    4. HTML Syntax

      1. HTML <script> Tag

        1. HTML <script> Tag With Inline JavaScript Code

          Last Updated: 4/14/2007
          Applies to:  JavaScript 1.0+

          JavaScript is most commonly used inside HTML pages, where it is wrapped in an HTML <script> element.  

          The <script> element can contain the actual JavaScript code, as:

                  <script language='JavaScript'>
                    <!-- Hide script from older browsers, as HTML comments.
          
                    // Global code that is executed as soon as it is found.
                    var i = 1;
                    alert("i = " + i);
                    // Function to do something useful.  Not executed until called.
                    function doSomething(evt, obj)
                    {
                      var i = 2;
                      alert("i = " + i);
                      return false;
                    }
                    //-->
                  </script>

          Note the HTML comment delimiters ("<!--" and "-->") used inside the <script> tag, but outside the JavaScript code.  This is for compatibility with really old browsers (1990's-era) that don't recognize the <script> tag.  Browsers typically ignore tags they don't recognize, but may still render the contents of the tag, so this prevents the JavaScript code from being shown to the user in a really old browser.

          Also, note the JavaScript comment delimiter ("//") before the HTML close comment delimiter ("-->").  This prevents the JavaScript interpreter from complaining about "-->" being invalid JavaScript code.

          --Fred

        2. HTML <script> Tag to Load a Separate JavaScript File

          Last Updated: 4/14/2007
          Applies to:  JavaScript 1.0+

          Instead of containing the JavaScript code, a <script> tag can mention the name of a separate file that contains the JavaScript code, as:

                  <script language='JavaScript' src='js/sourcefile.js'></script>

          The file is specified using a pathname relative to the current HTML filename, so the above would look in the "js" subfolder of the folder containing the HTML file.

          I don't recommend using the shorter HTML format (ending the start tag with "/>" and using no explicit end tag), because I've had trouble with it in some browsers:

                  <script language='JavaScript' src='js/sourcefile.js' />

          Since the default language is 'JavaScript', you can omit the language attribute, as:

                  <script src='js/sourcefile.js'></script>

          You can specify other scripting languages that are supported by some browsers:

                  <script language='PerlScript' src='perl/sourcefile.pl'></script>
                  <script language='VBScript' src='vb/sourcefile.bas'></script>
                  <script language='JScript' src='js/sourcefile.js'></script>

          You can even mention the explicit version of the scripting language, which may be necessary in scripting languages where different versions are not backward compatible, or where you are using the very latest features that only the latest version supports.  I've never used it, but I think the syntax is something like:

                  <script language='JScript 1.0' src='js/sourcefile.js'></script>
                  <script language='JScript 1.1' src='js/sourcefile.js'></script>

          Personally, I always specify the language explicitly, but leave out the version number.  I've had no problems yet with incompatibility between different versions of JavaScript.  Different versions of the DHTML object model, yes, but not different versions of JavaScript.

          Finally, there is a newer syntax, where the "language" attribute is deprecated in favor of a new "type" attribute that takes the standard MIME-type syntax, as:

                  <script type='text/javascript' src='js/sourcefile.js'></script>
                  <script type='text/ecmascript' src='js/sourcefile.js'></script>

          I haven't moved to that yet because the old syntax works fine in all browsers, but the new syntax doesn't work in old browsers.

          --Fred

    5. JavaScript Namespaces

      1. Creating a namespace

        Last Updated: 4/14/2007
        Applies to:  JavaScript 1.0+

        The problem:

        How to avoid name collisions in JavaScript?

        When you use only a couple of JavaScript functions and variables in a Web page, it is easy to avoid name collisions.  However, as you make more use of JavaScript, you start to accumulate a lot of functions and variables, and need naming conventions.  If you have multiple people writing them, conventions become even more important.  Then, as you start using JavaScript libraries written by other people, or even other companies or vendors, it becomes important that the naming convention be standardized around the world.  Even more so if you write your own JavaScript library and want it to work in a variety of environments.

        Other languages solve this problem via "namespaces" or "packages".  What to do in JavaScript, which doesn't offer these features?

        The solution:

        You can create the effect of a "namespace" in JavaScript by taking advantage of its dynamic nature to add all of your functions and variables to JavaScript objects.  Furthermore, you can mimic the Java naming convention (based on registered Internet domain names) to avoid collisions between unrelated people and organizations throughout the world.  Here's how.

        Since I own the "bristle.com" domain, the Java convention says that I should place all of my Java classes in packages with names that start with "com.bristle" like:

            com.bristle.javalib.util.StrUtil
            com.bristle.javalib.util.GetOpt
            com.bristle.javalib.log.Logger
            com.bristle.javaapps.scalejpg.ScaleJPG
            com.bristle.webapps.slideshow.SendImageServlet

        Since no one else in the world owns "bristle.com", there should be no collisions with anyone outside my organization.

        I do the same with my JavaScript library.  Instead of polluting the global namespace with functions like: 

                function doSomethingUseful(param1, param2)
                {
                    // Put useful code here.
                }

        I write:

                com.bristle.jslib.Util.doSomethingUseful = function(param1, param2)
                {
                    // Put useful code here.
                }

        This function can be called as:

                com.bristle.jslib.Util.doSomethingUseful(1, 2); 

        In the JavaScript source file, before I declare the function, I create the nested set of objects that will hold the function, as:

                var com = {};
                com.bristle = {};
                com.bristle.jslib = {};
                com.bristle.jslib.Util = {};        

        OK.  So far, so good.  But, what if someone else does the same, and also creates the starting "com" variable, as:

                var com = {};
                com.other = {};

        Their "com" object replaces my "com" object, and all of the "com.bristle..." stuff vanishes.  Not good.  The solution is for all of us to test the existence of the "com" object before creating it.  Therefore, I actually write the following:

                if (typeof(com) == "undefined") { eval("var com = {};"); }

        Furthermore, since my JavaScript library contains lots of different groups of functions, in lots of different files, with names like:

            com.bristle.jslib.Util.js
            com.bristle.jslib.Event.js
            com.bristle.jslib.Validate.js

        I start each file with the conditional creation of all of the required nested objects, plus the unconditional creation of the most nested object that will hold all the functions and variables in that file.  For example:

                if (typeof(com) == "undefined")               { eval("var com = {};"); } 
                if (typeof(com.bristle) == "undefined")       { eval("com.bristle = {};"); } 
                if (typeof(com.bristle.jslib) == "undefined") { eval("com.bristle.jslib = {};"); } 
                com.bristle.jslib.Util = {};

        I suggest you do the same, storing your own JavaScript functions and variables in nested objects named for domains you own. 

        --Fred

  2. DHTML

    1. DHTML Intro

      Last Updated: 4/17/2007
      Applies to:  JavaScript 1.0+

      Dynamic HTML (DHTML) is a technique that allows you to change the HTML in a Web page on the fly, after it has been sent from the Web server to the browser.  You still write the HTML as before, however, you add "id" attributes to those HTML elements that you want to manipulate dynamically, as:

              <table>
                <tr>
                  <td>abc</td>
                  <td id='tdACellICareAbout'>def</td>
                  <td>ghi</td>
                  <td id='tdAnotherCellICareAbout'>jkl</td>
                </tr>
              </table>

      Then you can manipulate the HTML elements from JavaScript code using the ids. For example:

              <script language='JavaScript'>
                alert(document.all.tdACellICareAbout.innerHTML);        // Shows def
                alert(document.all.tdAnotherCellICareAbout.innerHTML);  // Shows jkl
                document.all.tdACellICareAbout.innerHTML = '<b>xyz</b>';// Changes the cell to xyz (bold)
                document.all.tdAnotherCellICareAbout.innerHTML = 'pdq'; // Changes the cell to pdq
              </script>

      Whether or not you use DHTML, browsers create a Document Object Model (DOM) in memory to represent the HTML that was loaded into the page.  Browsers do this for every Web page, regardless of whether you specify any id attributes.  The DOM for the above example would consist of a "document" object, containing a "body" object, containing a "table" object, containing a "tr" object, containing 4 "td" objects, 2 of which happen to have ids.  

      The purpose of the id attributes is to make it easier for your JavaScript code to find specific DHTML DOM objects in this potentially huge hierarchy.  The syntax "document.all.tdACellICareAbout" tells the browser to find the HTML element with id "tdACellICareAbout" anywhere in the document.  The "innerHTML" property is a property of a DOM "td" object.  Once you've found the right "td" object, you can set its innerHTML to any string of text, even strings that contain more HTML element tags, and it will update the screen immediately.  In the example above, I replace the text of a cell with bolded text, but I could just as easily have replaced the text of the cell with an entire new table nested inside that cell. For more info about HTML elements and attributes, and their corresponding DHTML objects and properties, see:

          http://bristle.com/~fred/#html
          http://bristle.com/~fred/#dhtml

      --Fred

    2. Getting an HTML element to operate on

      Last Updated: 4/17/2007
      Applies to:  JavaScript 1.0+

      As shown in the above example, the syntax:

              document.all.myId

      is a way to search for an HTML element with an id value of "myId".  This is a convenient shortcut, but not really the official way to do it.  It is supported in Microsoft Internet Explorer, Mozilla Firefox, and perhaps other browsers, but not necessarily all browsers.  The official syntax is:

              document.getElementById("myId")

      However, the shortcut is gaining popularity, and will probably soon be supported by all browsers.  

      Another variation on the shortcut is:

              document.all["myId"]

      This form and the official syntax have one advantage over the simpler dotted form, which is that the id is specified as a string value, not as an implicit property name of the "all" property.  Since it is a regular string, you can manipulate the string, computing an id value, or even reading it from a file or something, before using it to get an HTML element.  For example:

              var intCounter = 1;
              strId = "myId" + intCounter;
              alert(document.all[strId].innerHTML);

      If you changed the last line to:

              alert(document.all.strId.innerHTML);

      you'd be trying to access the HTML element with id "strId", not "myId1".

      --Fred

    3. Name vs. Id

      Original Version: 4/17/2007
      Last Updated: 5/22/2007
      Applies to:  JavaScript 1.0+

      Don't confuse the "name" attribute and the "id" attribute.

      The "id" attribute of an HTML element is used in JavaScript code to refer to the element programmatically.  It is useful only when manipulating the HTML element as DHTML.

      The "name" attribute of an HTML element is different.  If an input-type element (input, textarea, select, etc.) has a name attribute, and is inside a form, then its name/value pair gets sent to the server when the form is submitted.  The name attribute predates the existence of DHTML and is useful in any HTML data entry page, regardless of whether DHTML and JavaScript are being used.

      These are two very different things.  However, lots of people confuse them, so browsers try to be helpful and accommodate the wrong one being used in some situations, so more people confuse them, etc.  You can get away with using the wrong one sometimes, but it is better to use them correctly.  Add an id to all elements you want to manipulate by id in JavaScript.  Add a name only when the element is supposed to send data to the server.

      When choosing ids and names for your HTML elements, keep in mind the different purposes that they serve.  One convention is to use the same value for name and id, but I don't think that is appropriate because it just adds to the confusion between the two.  

      Instead, I set the id to reflect the type of HTML control and other things known about it by the local JavaScript that manipulates it as an HTML element, and I set the name to reflect the meaning and data type of the value sent to the back end server code.  For example, if I have an HTML select that shows descriptive names to the user, but has DB keys as values, as:

              <select name='productKey' id='selProduct'>
                <option value='123'>Aspirin<option>
                <option value='127'>Tylenol<option>
                <option value='128'>Advil<option>
              </select>

      I might use a name of "productKey" to remind the server code that the request parameter by that name is a numeric database key, and an id of "selProduct" to remind the JavaScript code that it is an HTML select element and therefore has select-type properties like selectedIndex.  If I later change the UI so it is a set of checkboxes. I may change the id to "chkProduct", but I'd leave the name as "productKey".  Such "information hiding" and "separation of concerns" principles are important to large scale software development.

      Also, speaking of checkboxes, sometimes you have to give the same name to several HTML elements, so they send their data as expected, but you may still want separate ids for them, so the JavaScript can manipulate them separately.

      --Fred

    4. Getting dynamic style of an HTML element

      Last Updated: 4/17/2007
      Applies to:  JavaScript 1.0+

      Here is a Bristle Software JavaScript library function to get the current style of an HTML element.

      /******************************************************************************
      * Get the current style of the specified object.
      *
      * Note:  Can't just use the style property.  That is just the inline style 
      *        specified in the HTML.  This is much more accurate, including 
      *        default values, values set by linked or cascaded stylesheets, and
      *        values set dynamically via DHTML.
      * Note:  Can't just use the currentStyle property.  It is IE-specific.
      ******************************************************************************/
      com.bristle.jslib.Util.getStyle =
      function(obj)
      {
          return ((typeof(obj.currentStyle) != "undefined")
                  ? obj.currentStyle
                  : ((typeof(window.getComputedStyle) != "undefined")
                     ? window.getComputedStyle(obj,"")
                     : obj.style
                    )
                 );
      }

      --Fred

    5. Hiding/showing HTML elements

      Last Updated: 4/17/2007
      Applies to:  JavaScript 1.0+

      Here are Bristle Software JavaScript library functions to get and set the visibility of an HTML element.

      /******************************************************************************
      * Get the visibility of the specified object.
      ******************************************************************************/
      com.bristle.jslib.Util.isVisible =
      function(obj)
      {
          return !(com.bristle.jslib.Util.getStyle(obj).display == "none");
      }
      
      /******************************************************************************
      * Set the visibility of the specified object.
      ******************************************************************************/
      com.bristle.jslib.Util.setVisible =
      function(obj, blnValue)
      {
          // Note:  Set display property to "none" instead of setting visibility 
          //        property to "hidden".  Otherwise the display space consumed 
          //        by the element does not get reused.  The page does not reflow.
          //        The element is invisible but still consumes page space, per
          //        Danny Goodman O'Reilly Dynamic HTML book.
          // Note:  Set display property to "none" instead of setting visibility 
          //        property to "collapse", which is still not recognized by 
          //        Internet Explorer for Windows version 6.0, per Danny Goodman 
          //        O'Reilly Dynamic HTML book.
          obj.style.display = blnValue ? "inline" : "none";
      }

      --Fred

    6. Enabling/disabling HTML elements

      Last Updated: 4/17/2007
      Applies to:  JavaScript 1.0+

      Here are Bristle Software JavaScript library functions to get and set the disabled property of an HTML element.

      /******************************************************************************
      * Get the disabled property of the specified object.
      ******************************************************************************/
      com.bristle.jslib.Util.isDisabled =
      function(obj)
      {
          return obj.disabled;
      }
      
      /******************************************************************************
      * Set the disabled property of the specified object.
      ******************************************************************************/
      com.bristle.jslib.Util.setDisabled =
      function(obj, blnValue)
      {
          obj.disabled = blnValue;
      }

      --Fred

    7. Bolding/unbolding HTML text

      Last Updated: 4/17/2007
      Applies to:  JavaScript 1.0+

      Here are Bristle Software JavaScript library functions to get and set the bold property of an HTML element.

      /******************************************************************************
      * Get the boldness of the specified object.
      ******************************************************************************/
      com.bristle.jslib.Util.isBold =
      function(obj)
      {
          return (com.bristle.jslib.Util.getStyle(obj).fontWeight == "bold");
      }
      
      /******************************************************************************
      * Set the boldness of the specified object.
      ******************************************************************************/
      com.bristle.jslib.Util.setBold =
      function(obj, blnValue)
      {
          obj.style.fontWeight = blnValue ? "bold" : "normal";
      }

      --Fred

    8. Setting color

      Last Updated: 4/17/2007
      Applies to:  JavaScript 1.0+

      Here are Bristle Software JavaScript library functions to get and set the foreground and background colors of an HTML element.

      /******************************************************************************
      * Get the color of the specified object.
      ******************************************************************************/
      com.bristle.jslib.Util.getColor =
      function(obj)
      {
          return (com.bristle.jslib.Util.getStyle(obj).color);
      }
      
      /******************************************************************************
      * Set the color of the specified object.
      ******************************************************************************/
      com.bristle.jslib.Util.setColor =
      function(obj, strValue)
      {
          obj.style.color = strValue;
      }
      
      /******************************************************************************
      * Get the background color of the specified object.
      ******************************************************************************/
      com.bristle.jslib.Util.getBackgroundColor =
      function(obj)
      {
          return (com.bristle.jslib.Util.getStyle(obj).backgroundColor);
      }
      
      /******************************************************************************
      * Set the background color of the specified object.
      ******************************************************************************/
      com.bristle.jslib.Util.setBackgroundColor =
      function(obj, strValue)
      {
          obj.style.backgroundColor = strValue;
      }

      --Fred

  3. DOM Events

    1. Handling Events

      1. Handling Events via HTML Attributes

        Last Updated: 11/1/2007
        Applies to:  JavaScript 1.0+

        Various "events" occur in the Web browser, in response to user interactions, timers, pages loading, etc, and you can assign snippets of JavaScript code to "handle" the events.

        Some particularly useful events include:

        Type Events
        Web page load, unload, resize
        Mouse buttons click, dblclick, mousedown, mouseup
        Mouse pointer mousemove, mouseover, mouseout
        Keyboard keypress, keydown, keyup, blur, focus
        Data entry fields change, select

        The typical way to assign an event handler is via the HTML "on" event handler attributes of the HTML elements.  For example, to cause the JavaScript routine objBody_onLoad() to be called when the Web page finishes loading:

                <body id='objBody' onload='return objBody_onLoad(event, this)'>

        Similarly:

                <input id='txtName'
                       type='text' 
                       onchange='return txtName_onChange(event, this)'
                       onkeyup='return txtName_onKeyUp(event, this)'
                       onmouseup='return txtName_onMouseUp(event, this)'
                       onmousemove='return txtName_onMouseMove(event, this)'
                       onmouseover='return txtName_onMouseOver(event, this)'
                       onmouseout='return txtName_onMouseOut(event, this)'
                       />

        causes the various specified routines to be called whenever the text field value changes, when a keyboard or mouse key is released in the text box, when the mouse moves within the text box, and when the mouse moves into or out of the text box.

        Notes:

        1. The value of each "on" attribute can be a quoted string containing any JavaScript snippet.  However, I always use a simple call to a single JavaScript function that contains the JavaScript code that I could otherwise have put directly into the quoted string.  This makes my HTML simpler and easier to read, keeping the JavaScript code in a separate function, which can even reside in a separate JavaScript file.
        2. If you use such a JavaScript function as an event handler, it can have any name.  For the sake of readability and maintainability, I always name mine with the exact id of the object, followed by "_on", followed by the exact name of the event in mixed upper and lower case.  (This is the same convention used by VBScript to automatically find the event handler if you don't specify the "on" attribute.)  This convention documents the situation in which each JavaScript function is called, so I don't need to mention that in my comments.  The comment header I put on each such JavaScript function explains what it does when called, but not what causes it to be called.
        3. You can pass any parameters to the JavaScript function.  I always pass the two special variables event and this.  These are the event that occurred to cause the handler to be called and the object to which the event occurred.  Both of these have useful properties and methods that can be accessed from within the JavaScript function.  For example, when the event is a mousemove event, it has properties to specify the exact location of the mouse pointer, and when the event is a keyup event, it has properties to specify which key was released.  Also, the object has properties and methods to get/set its color, visibility, etc. 
        4. I always put the keyword return in front of the call to the JavaScript function.  This returns the value of the JavaScript function to the browser, which makes it possible for the JavaScript function to cancel the event by returning false.  For example, you can cancel a keyup event whenever the key was anything except a numeric digit to prevent the user from entering non-numeric values into a text box. 

        Here's an example of such an event handler.  It turns the text field red when the mouse moves into it.

                function txtName_onMouseOver(evt, obj)
                {
                    obj.style.backgroundColor = "red";
                    return true;
                }

        --Fred

      2. Handling Events via DOM Properties

        Last Updated: 11/1/2007
        Applies to:  JavaScript 1.0+

        Another way to assign an event handler is via the "on" properties of the DOM objects.  For example:

                txtName.onchange = txtName_onChange;

        This DOM property approach is more dynamic than the HTML attribute approach because you can assign a new event handler on the fly.  Also, this approach allows you to assign event handlers to objects that don't occur in the HTML, like the document itself.

        However, it requires that you specify the name of a JavaScript function, without specifying what parameters to pass.  In most browsers, such an event handler is always called with one parameter -- the event.  In Internet Explorer, such an event handler is called with no parameters, so you have to use the global window.event object to determine the current event.  Once you know the event, you can determine the object to which the event occurred via the event.target property in most browsers.  In Internet Explorer, you must use the event.srcElement property.  

        If the event handler is assigned in this way, it has more work to do:

                function txtName_onMouseOver(evt)
                {
                    // Get event, which IE does not pass.
                    if (typeof(evt) == "undefined")
                    {
                         evt = window.event;
                    }
        
                    // Get the object to which the event occurred.
                    var obj;
                    if (typeof(evt.target) != "undefined")
                    {
                        // Most browsers
                        obj = evt.target;
                    }
                    else if (typeof(evt.srcElement) != "undefined")
                    {
                        // Internet Explorer
                        obj = evt.srcElement;
                    }
                    else 
                    {
                        // Can't tell which object.  What to do?
                        return true;
                    }
        
                    // Finally, set the color to red.
                    obj.style.backgroundColor = "red";
                    return true;
                }

        --Fred

    2. Getting the Event keyCode

      Last Updated: 11/1/2007
      Applies to:  JavaScript 1.0+

      Here is the Bristle Software JavaScript library function to determine which key was pressed in a keyboard event:

      /******************************************************************************
      * Get the keyCode from the specified event.
      *
      *@param evt     The event containing the keyCode
      *@return        The keyCode, or null.
      *@throws        None.
      ******************************************************************************/
      com.bristle.jslib.Event.getEventKeyCode =
      function(evt)
      {
          if (!evt) return null;
          if (evt.keyCode && evt.keyCode != 0)
          {
              return evt.keyCode;
          }
          else if (evt.charCode)      // Netscape uses charCode, not keyCode, for
                                      // some events.
          {
              return evt.charCode;
          }
          else
          {
              return null;
          }
      }

      --Fred

  4. Controlling the Browser

    1. Disabling the Backspace key

      Last Updated: 11/1/2007
      Applies to:  JavaScript 1.0+

      Want a way to prevent the Backspace key from clicking the browser Back button in your Web application?

      Problem:

      Modern Web applications often have large complex data entry screens.  Your user may spend a significant amount of time filling them out before finally submitting them to the Web server.  Much of the data is entered via text fields, which means he is likely to hit the Backspace key often. However, the default browser behavior when he hits Backspace outside of a text box is to click the browser's Back button.  Once the back button has been clicked, there is no way for you, the JavaScript programmer, to prevent the browser from discarding the current page and returning to the previous page. The best you can do is take some action on the way out, like prompting the user and attempting to save the data if it has no validation errors.  This is a common and frustrating user error.

      Solution:

      The solution is to disable the Backspace key as a shortcut for the Back button, on all of your complex data entry screens, taking care to not disable its main function of deleting typed characters.  With the Backspace key disabled, your user can still return to the previous page by hitting Alt-Left Arrow, or by clicking on the Back button with the mouse, which he is less likely to do by accident.

      Here is the Bristle Software JavaScript library code to prevent Backspace from causing a browser Back operation.  To use it, simply put the following call in your objBody_onLoad() event handler:

          com.bristle.jslib.Event.disableBackspaceAsBrowserBackButton();

      and paste the following (along with the getEventKeyCode() routine from the previous tip) into the HTML page or an included JavaScript source file:

      com.bristle.jslib.Event.intKEYCODE_BACKSPACE   = 8;
      
      /******************************************************************************
      * Return true if the specified event is the Backspace key.
      *
      *@param evt     The event containing the keyCode
      *@return        True if the event was the Backspace key.
      *@throws        None.
      ******************************************************************************/
      com.bristle.jslib.Event.isBackspaceKey =
      function(evt)
      {
          if (com.bristle.jslib.Event.getEventKeyCode(evt) == 
                                          com.bristle.jslib.Event.intKEYCODE_BACKSPACE)
          {
              return true;
          }
          return false;
      }
      
      /******************************************************************************
      * Return false if the specified event is the Backspace key as a shortcut for 
      * the browser Back button, true if it is being used to delete chars in an 
      * enabled text box or if it is not a Backspace at all.
      *
      *@param evt Event to check for backspace key.
      ******************************************************************************/
      com.bristle.jslib.Event.isNotBackspaceAsBrowserBackButton = 
      function(evt) 
      {
          // Get event which IE does not pass as a param like other browsers do.
          if (typeof(evt) == "undefined")
          {
               evt = window.event;
          }
      
          if (!com.bristle.jslib.Event.isBackspaceKey(evt))
          {
              return true;
          }
      
          // Note: None of these are needed.  Returning false is sufficient.
          // if (typeof (evt.returnValue) != "undefined")
          // {
          //     evt.returnValue = false;
          // }
          // if (typeof (evt.cancelBubble) != "undefined")
          // {
          //     evt.cancelBubble = true;
          // }
          // if (typeof (evt.stopPropagation) != "undefined")
          // {
          //     evt.stopPropagation();
          // }
          // if (typeof (evt.keyCode) != "undefined")
          // {
          //     evt.keyCode = 0;
          // }
      
          // Get the HTML element in which Backspace was typed.
          var targetNode;
          if (typeof(evt.target) != "undefined")
          {
              // Most browsers
              targetNode = evt.target;
          }
          else if (typeof(evt.srcElement) != "undefined")
          {
              // Internet Explorer
              targetNode = evt.srcElement;
          }
          else 
          {
              // Can't tell where the Backspace was pressed.  Don't cancel it.
              return true;
          }
      
          // Don't cancel Backspace for these HTML elements except when they
          // are readonly.  When not readonly, they make good use of Backspace 
          // (to delete chars), and they prevent it from causing the browser 
          // Back operation anyhow.
          // Cancel Backspace for all other HTML elements.
          var strNodeName = targetNode.nodeName;
          if (   (strNodeName == "INPUT" || strNodeName == "TEXTAREA")
              && !targetNode.readOnly)
          {
              return true;
          }
          else
          {
              return false;
          }
      }
      
      /******************************************************************************
      * Disable the Backspace key as a shortcut for the browser Back button, 
      * but allow it to delete chars in enabled text boxes.
      ******************************************************************************/
      com.bristle.jslib.Event.disableBackspaceAsBrowserBackButton =
      function()
      {
          // Note: This must be assigned via the onkeydown property of the document
          //       object, not as an HTML attribute of the HTML body element.
          //       Otherwise, it doesn't work in IE 6.0.2800.1106.
          document.onkeydown=com.bristle.jslib.Event.isNotBackspaceAsBrowserBackButton;
      }

      --Fred

    2. Showing a temporary statusbar message

      Last Updated: 11/8/2007
      Applies to:  JavaScript 1.0+

      Here is the Bristle Software JavaScript library function to display a text message in the statusbar of the browser, temporarily for the specified number of seconds:

      /******************************************************************************
      * Show a text message in the status bar of the browser's window, optionally
      * clearing it after a specified number of seconds.
      * Note: In Internet Explorer IE 6.0.2800.1106, the screen is updated to show
      *       the status immediately.  In Firefox 2.0.0.9, the screen is updated
      *       only after the currently running JavaScript code completes and
      *       control is returned to the browser.  Therefore, in Firefox, this is
      *       not useful for showing the status of multiple steps in a single
      *       long-running block of JavaScript code inside a single event handler.
      * Anticipated Changes:
      * - Does not yet check for apostrophe chars in the message, or any other
      *   chars that could cause syntax errors in calling setTimeout.  For now,
      *   the caller should double all apostrophes.
      *
      *@param strMessage  Message to show
      *@param intSeconds  Number of seconds before clearing the message.
      *                   Optional.  Default: Don't clear it.
      ******************************************************************************/
      com.bristle.jslib.Util.strStatusBarMessageToBeCleared = "";
      com.bristle.jslib.Util.showStatusBarMessage =
      function(strMessage, intSeconds)
      {
          window.status = strMessage;
          if (typeof(intSeconds) != "undefined")
          {
              // Schedule a code snippet after the specified number of seconds
              // that will clear the status bar only if the original message is
              // still being shown at that time.
              // Note: Prefix intSeconds with "0" and use parseInt() to guarantee
              //       a valid numeric value, defaulting to zero.
              com.bristle.jslib.Util.strStatusBarMessageToBeCleared = strMessage;
              intSeconds = parseInt("0" + intSeconds, 10);
              window.setTimeout
                  (  "if (com.bristle.jslib.Util.strStatusBarMessageToBeCleared"
                   + "    == '" + strMessage + "') "
                   + "{ com.bristle.jslib.Util.showStatusBarMessage(''); }"
                  ,intSeconds * 1000
                  ,"JavaScript");
          }
      }

      --Fred

  5. Ajax

    1. Ajax Intro

      1. What is Ajax?

        Original Version: 3/31/2007
        Last Updated: 12/10/2007
        Applies to:  JavaScript 1.0+, IE 5.5+, Firefox 1+, Netscape 7+, Safari 1+

        Ajax is a technique, not a programming language or any other new technology.  It requires no additional software.

        The Ajax technique can be used in any Web application, regardless of whether the server-side code is written in Java, .NET, Ruby on Rails, PHP, Perl, C/C++, or whatever.

        The term "Ajax" was coined in 2005 to describe a technique that some JavaScript programmers had been using since 1997 or so, and that I personally started using in 2000.  It stands for "Asynchronous JavaScript and XML".  The dramatic use of this technique by Google Maps in 2005, and the subsequent coining of a catchy name, has catapulted Ajax into the mainstream of Web programming.

        Ajax allows a Web page to go back to the server for more data without the user being aware of it, and without having to rebuild the whole web page and lose the user's context.  For example, Google Maps uses it to allow you to drag a map and have new map regions scroll into view.  It is typically implemented via JavaScript code using the XMLHttpRequest object (which is built into all modern browsers) to get data from the server, and then using DHTML (Dynamic HTML, which is also built into all modern browsers) to update the current Web page.

        However, the name is somewhat of a misnomer because Ajax:

        1. Can be synchronous or asynchronous, though asynchronous is most common.
        2. Does not necessarily involve JavaScript.  The client-side code is typically written in JavaScript, but could also be PerlScript, ActiveScript, VBScript, or many other client-side browser scripting languages.
        3. Does not necessarily use XML.  It is commonly used to transmit XML, JSON, plain text, or any other data format.

        Furthermore, Ajax is not limited to running in Web browsers.  The same technique can be used to access Web services from within any application that is capable of creating and using either the standard XMLHttpRequest object or the Microsoft MSXML ActiveX object to access data from a Web service.  Therefore, it can be used from:

        1. VBA in MS Word, Excel and PowerPoint
        2. LotusScript in Lotus Notes
        3. AutoLisp in AutoCAD
        4. etc.  

        It can also be used in your own custom client applications, written in Java, C, C++, C#, VB, etc.  It can even be used in your server-side applications to access Web services on other servers. 

        --Fred

      2. Why use Ajax?

        Original Version: 3/31/2007
        Last Updated: 12/10/2007

        There are several business-oriented (non-geeky) reasons to use Ajax:
        1. Users demand it
          Ajax is not just another cool but geeky technique that programmers foist off on their users.  It is something that the users demand to have, once they've seen it.  It allows for very user-visible effects that provide a very rich user interface within a Web page.  Once they've used Ajax-driven Web pages, they'll never be satisfied with the old way again.
        2. Portable across browsers
          With slight variations that are easily worked around, Ajax is built into all modern Web browsers.
        3. Zero-install, no "DLL Hell"
          Because it is already built into the web browser, Ajax is already installed on every client computer.  Your Web application, including its Ajax code can already be used from any computer, with no need to install Ajax itself or any of your Ajax code.  Therefore, there is no "DLL Hell", where an install of one app can break another previously installed app.
        4. Flexibility and Speed
          Ajax allows a clean separation of data from the user interface, providing new options in choosing the right mix of static and dynamic pieces to achieve the right mix of flexibility and efficiency.

          In traditional client/server apps, the forms, controls, and code are typically static, and the data is dynamic.  For example, a static form, with a static table, and a static set of buttons, typically shows a dynamic set of data.  Each user interaction continues to use the same form, table, and buttons, but may load new data.  This is very efficient, but not very flexible.

          In traditional web apps, on the other hand, the forms, controls, code, and data are all dynamic.  For example, the Web server runs code that dynamically generates a form, with a table and a set of buttons, and dynamically generates the data to show in the table.  Each user interaction regenerates the form, table, and buttons, in addition to loading new data.  This is very flexible, but not very efficient.  As a result it is noticeably slow.  Users have come to tolerate the slowness because of the other advantages that Web apps offer (zero install, portability, etc.)

          Ajax offers the best of both worlds.  The data can be dynamic, while the forms, controls, and code are any mix of static and dynamic.  Like a traditional client/server app, the Ajax app can load the forms, controls, and code once, and just change the data dynamically.  The entire Ajax app can run inside a single Web page, loaded once from the server, with Ajax going back to the server occasionally for new data only.  Or, like a traditional web app, the Ajax app can go back to the server more often for new pages, containing new forms, controls, code, and data.  Or, Ajax can dynamically modify the forms, controls, code and data on the fly, without loading a new Web page from the server.

        This last reason may seem like a geeky reason, because the users don't typically care about such separation.  However it really is a business-oriented reason because it allows the Ajax app to create a much better user interface.  This is the reason that really causes users to demand Ajax.

        There are also some truly geeky reasons to use Ajax.  The users don't care about these reasons and may never understand how they contribute to the user experience, but the programmers do.

        1. Multi-threaded data retrieval from Web servers
          Traditional Web apps are single-threaded, except for the concurrent loading of images.  JavaScript has always allowed multiple threads to do cosmetic things like animations of banners and such.  However, Ajax finally allows multi-threaded access to the Web server and through it to the database.  This allows you to do things like:
          1. Pre-fetch data before needed
            You can pre-fetch data before it is needed to create the appearance of speed.  This is the secret of much of the success of Google Maps.  It doesn't wait for you to drag left, right, up, or down before fetching the additional map data in that direction.  It pre-fetches some in each direction, and then continues pre-fetching in the direction you are currently going.
          2. Progress indicators
            Ajax operations provide "callbacks" for your JavaScript code to be notified that progress is being made, not only that the entire operation succeeded or failed.  You can use these callbacks to manage an animated progress indicator to give the user feedback about the ongoing operation.
          3. Partial data load
            You can load a subset of the data requested by the user, and allow the user to begin viewing and editing that data, while you continue to load more data behind the scenes.
          4. No need for window.setTimeout()
            Since Ajax has built is support for both synchronous and asynchronous operation, you don't need to use window.setTimeout() to explicitly create a new thread for it.
        2. "Mashups" -- Merged data from multiple Web servers
          Ajax allows you to retrieve data from multiple Web servers and merge it all into one Web page, a technique that has recently been named a "mashup".  This has led to a proliferation of Web sites that show real estate data, classified ads, etc. all superimposed over a Google map.  You can write your own mashup to merge data from a variety of sources in any way you like.  Many Web sites now explicitly offer their data as Web Services and other XML streams to make it more convenient for you to use their data.
          Note: For Web browser security reasons, the Ajax code can't go directly to the various servers, so you'll have to funnel it all through your own Web server, the one that served the main page to the browser.  Alternatively, you can bypass the browser security by rolling your own Ajax via the SRC property of the HTML IFRAME and SCRIPT tags instead of using the XMLHttpRequest object.  Finally, if you only have a limited set of users, you can have them change their browser security settings to be less restrictive.
        3. Less bandwidth required; less server load
          Ajax allows you to go back to the Web server much more often, but for much smaller chunks of data.  You can fetch a partial page, or even just new data to insert into a page, without having to re-fetch the entire page.  The result can be much less total traffic to the Web server, reducing both the load on the server and the bandwidth requirements.

        --Fred

      3. How much to use Ajax?

        Original Version: 3/31/2007
        Last Updated: 12/10/2007

        Ajax is not an all-or-nothing proposition.  You don't have to abandon all of your old Web software and convert everything to Ajax.  It is just one more technique in your programming bag of tricks.  Take an existing app, and add a few jazzy effects via Ajax.  If that works out well, begin adding more.  No major re-write required.

        In subsequent tips, I'll be showing details of how to use Ajax to:

        1. Send a periodic "keep-alive" to the Web server, to keep the server session from timing out while your user temporarily walks away from a complex form that is halfway filled out.
        2. Drill down into data, showing more detail.
        3. Do validation of data entry fields at the server on the fly, even at each user keystroke.
        4. Continue adding to the bottom of an HTML table while the user interacts with the top of it.
        5. etc.

        --Fred

      4. See Also

        Original Version: 3/31/2007
        Last Updated: 12/10/2007

        For more info on Ajax, see the Ajax row of my links page:

            http://bristle.com/~fred/#ajax

        For a quick intro to Ajax, see my PowerPoint presentation at:

            http://bristle.com/~fred/ajaxdemo/AJAXIntro.ppt

        For a variety of Ajax demos see:

            http://bristle.com/~fred/#ajax_demos

        1. A very simple demo I wrote myself
        2. A collection of small demos in a single page by Steve Benfield
        3. Google Suggest (like regular Google, but pre-fetches results)
        4. Google Maps (pre-fetches map data)
        5. Google Finance (dynamically loads stock data)
        6. Language translation (translate words as you type them)
        7. Mouse gesture as password (track the mouse motion via Ajax)
        8. Typing speed as password (measure time between keystrokes)
        9. Classified ads tied to a map

            http://bristle.com/~fred/#mashups

        1. HousingMaps (Google Maps + CraigsList)
        2. MashMap (Google Maps + ShowTimes)
        3. Zillow (Google Maps + Real Estate)

        Remember, since it is all JavaScript embedded in the Web page, you can see how they do it via View Source, as explained in my tips: 

                View Source
                View Source of Referenced JavaScript and CSS Files
                Firefox View Live Source

        --Fred

    2. Simple Ajax Example

      Original Version: 12/4/2007
      Last Updated: 12/13/2007
      Applies to:  JavaScript 1.0+

      Here is a simple complete example of JavaScript code that uses Ajax:

              var xhr = new XMLHttpRequest();
              xhr.onreadystatechange = myHandler;
              xhr.open("GET", "my_servlet", true);
              xhr.send("p1=abc");
      
              ...
      
              function myHandler() 
              {
                  if (xhr.readyState == 4) 
                  {
                      doSomethingWith(xhr.responseXML);
                  }
                  else if (xhr.readyState == 3)
                  {
                      showProgressIndicator();
                  }
              }

      In subsequent tips, I'll explain what is going on here, and show a slightly different version of the first line that is required by Microsoft Internet Explorer.  But, generally speaking, it really is that simple.

      --Fred

    3. XMLHttpRequest Methods

      Last Updated: 12/5/2007
      Applies to:  JavaScript 1.0+

      These are all of the methods of the XMLHttpRequest object:

          open ("method", "URL", [async, username, password])
                  Assigns destination URL, method, etc.

          send (params)
                  Sends request including postable string or DOM object data

          abort ()
                  Terminates current request

          getAllResponseHeaders ()
                  Returns headers (name/value pairs) as a string

          getResponseHeader ("header")
                  Returns value of a given header

          setRequestHeader ("label","value")
                  Sets Request Headers before sending

      --Fred

    4. XMLHttpRequest Properties

      Original Version: 12/5/2007
      Last Updated: 1/11/2008
      Applies to:  JavaScript 1.0+

      These are all of the properties of the XMLHttpRequest object:

          onreadystatechange
                  Event handler (your code) that fires at each state change

          readyState
                  0 = uninitialized
                  1 = loading
                  2 = loaded
                  3 = interactive 
         
                       (Some data has been returned.  In IE, the event 
                           handler fires only once.  In all other browsers,
                           it fires periodically, so you can show a progress bar.)
                  4 = complete

          status
                  HTTP status code returned from server.
                  200-299 = OK

          statusText
                  Message text to go with HTTP status code

          responseText
                  String version of data returned from server

          responseXML
                  XML DOM document of data returned

      --Fred

    5. Bristle Ajax Library

      1. Create an Ajax Object

        Original Version: 12/12/2007
        Last Updated: 1/10/2008
        Applies to:  JavaScript 1.0+, IE 5.5+, Firefox 1+, Netscape 7+

        Generally speaking, the Ajax object is the same in all browsers.  

        However, there is one notable exception.  Microsoft Internet Explorer does not yet support the standard way of creating the object, and requires browser-specific code.  Once created, the Ajax object supports the same properties and methods in all browsers, so only the creation code has to be browser-specific.

        Therefore, the Simple Ajax Example is not portable.  It works fine in all browsers except Internet Explorer, where the first line must be changed to the Microsoft way of creating the Ajax object.

        To simplify things, it makes sense to have a single routine that supports creation in any browser, so you can change the first line of Simple Ajax Example from:

        	var xhr = new XMLHttpRequest();

        to something portable but equally simple like:

        	var xhr = com.bristle.jslib.Ajax.Util.createAjaxObject();

        Here is a Bristle Software JavaScript Library routine that does just that:

        /******************************************************************************
        * Returns a new XMLHttpRequest object for use with Ajax operations.
        *
        *@throws com.bristle.jslib.Exception.intEXC_UNABLE_TO_CREATE_AJAX_OBJECT
        ******************************************************************************/
        com.bristle.jslib.Ajax.Util.createAjaxObject =
        function()
        {
            var xhr = null;
            if (window.XMLHttpRequest) 
            {
                // Create XMLHttpRequest object in most browsers.
                xhr = new XMLHttpRequest();
            }
            else if (window.ActiveXObject)
            {
                // Create XMLHttpRequest object in Microsoft browsers.
                try 
                {
                    // Newer versions of Internet Explorer
                    xhr = new ActiveXObject("Msxml2.XMLHTTP");
                }
                catch (e1)
                {
                    try 
                    {
                        // Older versions of Internet Explorer
                        xhr = new ActiveXObject("Microsoft.XMLHTTP");
                    }
                    catch (e2)
                    {
                        throw new com.bristle.jslib.Exception.Exception
                        (com.bristle.jslib.Exception.intEXC_UNABLE_TO_CREATE_AJAX_OBJECT
                        ,"Unable to create Ajax object"
                        ,"com.bristle.jslib.Ajax.Util.createAjaxObject"
                        );
                    }
                }
            }
            else
            {
                throw new com.bristle.jslib.Exception.Exception
                (com.bristle.jslib.Exception.intEXC_UNABLE_TO_CREATE_AJAX_OBJECT
                ,"Unable to create Ajax object"
                ,"com.bristle.jslib.Ajax.Util.createAjaxObject"
                );
            }
            return xhr;
        }

        --Fred

      2. Register Ajax Callbacks

        Original Version: 12/12/2007
        Last Updated: 12/13/2007
        Applies to:  JavaScript 1.0+, IE 5.5+, Firefox 1+, Netscape 7+

        As shown in Simple Ajax Example, the next step after creating the Ajax object is typically to register the "onreadystatechange" callback function that will be called at various times as the Ajax object changes state from "uninitialized" to "loading" to "loaded" to "interactive" and finally to "complete".  This single callback is called multiple times, once at each state change.  In all browsers except Microsoft Internet Explorer, it is also called periodically as the request is being processed but remains in the "interactive" state, so that you can use it to maintain a visual progress bar or something.

        Unfortunately, there is no built-in support for a timeout (if the server is too slow or never responds to the Ajax request).  Also, you typically have to write standard boilerplate code inside the single callback to check the readyState property to determine each time why the callback was called, and to check the HTTP status code to see whether a completed Ajax request succeeded or failed. 

        It makes sense to have a single routine that supports timeouts, and supports different callbacks for different situations, with simple calls like:

        	com.bristle.jslib.Ajax.Util.registerAjaxCallbacksAndStartTimer
        		(xhr
                	,callbackSuccess
                	,callbackFailure
                	,10000 // Timeout in 10 seconds
                	,callbackTimeout
                	,callbackInteractive
                	,callbackLoaded
                	,callbackLoading
                	,callbackUninitialized);

        Then Simple Ajax Example can be re-written as:

                var xhr = com.bristle.jslib.Ajax.Util.createAjaxObject();
        	com.bristle.jslib.Ajax.Util.registerAjaxCallbacksAndStartTimer
        		(xhr
                	,doSomethingWith
                	,null
                	,null
                	,null
                	,showProgressIndicator);
                xhr.open("GET", "my_servlet", true);
                xhr.send("p1=abc");

        Here is a Bristle Software JavaScript Library routine to do that:

        /******************************************************************************
        * Registers the specified functions as callbacks for the specified 
        * XMLHttpRequest object, and starts the timeout timer.  The callback functions 
        * will be called asynchronously in response to the various state changes of 
        * the XMLHttpRequest as it processes Ajax requests.
        *
        * Notes:
        * - Each callback is optional.  Trailing callback params can be omitted 
        *   entirely.  When not omitted, each callback can be specified as null, 
        *   or as a JavaScript function with the signature:
        *       function(XMLDOM, XMLHttpRequest)
        *   where the 1st parameter is the XML DOM Document returned by the 
        *   responseXML property of the XMLHttpRequest, and the 2nd parameter is
        *   the XMLHttpRequest object itself.  The 2nd parameter is optional, 
        *   which allows callbacks to ignore the XMLHttpRequest object and simply
        *   operate on the XML DOM Document passed in the 1st parameter, as:
        *       xmlDOM.getElementsByTagName("name")[0].firstChild.nodeValue
        *   More advanced callbacks can use the 2nd parameter to access the other 
        *   methods of the XMLHttpRequest object:
        *       abort()
        *       getResponseHeader()
        *       getAllResponseHeaders()
        *       etc.
        *   and the other properties:
        *       readyState
        *       status
        *       statusText
        *       responseText
        *       etc.
        *   These can be especially useful if the same callback is registered to 
        *   handle multiple states, or both success and failure statuses of the 
        *   Complete state.  Or to handle non-XML responses like HTML, JSON, or plain
        *   text, by using responseText instead of responseXML.  Also, callbacks
        *   other than callbackSuccess will receive a null XML DOM and may have to 
        *   use the XMLHttpRequest parameter to determine the details of the
        *   HTTP progress or failure. 
        *
        *@param xhr                 The XMLHttpRequest object
        *@param callbackSuccess     Function to be called when the state is Complete, 
                                    and the HTTP status indicates success.
        *@param callbackFailure     Function to be called when the state is Complete, 
                                    and the HTTP status indicates failure.
        *@param intTimeoutMillisecs Number of seconds before aborting the Ajax call
        *                           and calling callbackTimeout.
        *                           Optional.  Default=0 which means wait forever.
        *@param callbackTimeout     Function to be called if the Ajax call times out.
        *@param callbackInteractive Function to be called when the state is Interactive
        *@param callbackLoaded      Function to be called when the state is Loaded
        *@param callbackLoading     Function to be called when the state is Loading
        *@param callbackUninitialized
        *                           Function to be called when the state is Uninitialized
        *@return  Handle to setTimeout() used for callbackTimeout so it can be 
        *         canceled by the caller via clearTimeout() if necessary.
        ******************************************************************************/
        com.bristle.jslib.Ajax.Util.AJAX_STATE_COMPLETE      = 4;
        com.bristle.jslib.Ajax.Util.AJAX_STATE_INTERACTIVE   = 3;
        com.bristle.jslib.Ajax.Util.AJAX_STATE_LOADED        = 2;
        com.bristle.jslib.Ajax.Util.AJAX_STATE_LOADING       = 1;
        com.bristle.jslib.Ajax.Util.AJAX_STATE_UNINITIALIZED = 0;
        com.bristle.jslib.Ajax.Util.HTTP_STATUS_SUCCESS = 200;
        com.bristle.jslib.Ajax.Util.registerAjaxCallbacksAndStartTimer =
        function(xhr
                ,callbackSuccess
                ,callbackFailure
                ,intTimeoutMillisecs
                ,callbackTimeout
                ,callbackInteractive
                ,callbackLoaded
                ,callbackLoading
                ,callbackUninitialized)
        {
            // Schedule a call to callbackTimeout.
            // Note: Use a closure (anonymous function) to keep track of which 
            //       XMLHttpRequest to pass to callbackTimeout when there are multiple
            //       XMLHttpRequests instead of one global singleton.
            // Note: Shouldn't really start the timer until we make the Ajax call.  
            //       Not now, when we are just registering the callbacks.  Should move 
            //       this code to getAjaxXML().  But, the callbacks need to know what 
            //       timer to cancel when the Ajax completes with failure or success, 
            //       so we need a handle to the timer when creating the callbacks, 
            //       and we don't know how get a handle to a timer without starting 
            //       the timer.  Could wrap the timer in another object that creates it
            //       when told and keeps a handle to it, and could then pass a handle
            //       to that timer to the callbacks.  Maybe later.  For now, this is
            //       sufficient, since most use is via getAjaxXML() which makes the
            //       Ajax call immediately after registering the callbacks.
            var timer = null;
            if (intTimeoutMillisecs != null 
                && typeof(intTimeoutMillisecs) != "undefined"
                && intTimeoutMillisecs > 0 )
            {
                timer = window.setTimeout
                   (function() 
                    {
                        if (callbackTimeout != null 
                            && typeof(callbackTimeout) != "undefined")
                        {
                            callbackTimeout(null, xhr);
                        }
                        xhr.abort();
                    }
                   ,intTimeoutMillisecs
                   ,"JavaScript"
                   );
            }
        
            // Note: Use a closure (anonymous function) to keep track of which 
            //       XMLHttpRequest to pass to the callbacks when there are multiple
            //       XMLHttpRequests instead of one global singleton.
            var callback = null;
            xhr.onreadystatechange = 
            function()    
            {
                // Determine which callback to call.
                if (xhr.readyState == com.bristle.jslib.Ajax.Util.AJAX_STATE_COMPLETE)
                {
                    // Cancel the timeout immediately.  The operation has completed.
                    // Note: The completion may have been caused by the timer's call
                    //       to xhr.abort(), so the timer may already have fired.
                    //       Canceling it after it fires is not a problem.
                    if (timer != null)
                    {
                        window.clearTimeout(timer);
                    }
        
                    // Catch any errors that occur while trying to determine the 
                    // reason for the completion of the operation.  Reasons can be:
                    // 1. Normal completion with successful HTTP status code.
                    // 2. Normal completion with error HTTP status code.
                    // 3. Call to xhr.abort()
                    //    Note: We could probably prevent this case, if we ever needed 
                    //          to, by changing the value of xhr.onreadystatechange to 
                    //          no longer refer to this code before calling xhr.abort().
                    // 4. HTTP server was already down or inaccessible when Ajax call
                    //    was made.
                    // 5. HTTP server went down or became inaccessible before Ajax call
                    //    completed normally.
                    // We test xhr.status to distinguish between cases 1 and 2.
                    // However, with Firefox 2.0.0.10, testing it in cases 3, 4, and 5 
                    // causes an exception:
                    //        Component returned failure code: 0x80040111 
                    //        (NS_ERROR_NOT_AVAILABLE) [nsIXMLHttpRequest.status]
                    // to be thrown.
                    try
                    {
                        if (xhr.status == com.bristle.jslib.Ajax.Util.HTTP_STATUS_SUCCESS)
                        {
                            callback = callbackSuccess;
                        }
                        else
                        {
                            callback = callbackFailure;
                        }
                    }
                    catch(exception)
                    {
                        // Treat exception while checking status as a failure.
                        // This is to act the same in browsers where such an 
                        // exception occurs as in browsers where it does not.
                        // Since something has gone wrong that causes an exception 
                        // in some browsers, other browsers would most likely not
                        // have found an HTTP success code, and would have treated
                        // this as a failure.
                        callback = callbackFailure;
                    }
                }
                else if (xhr.readyState == com.bristle.jslib.Ajax.Util.AJAX_STATE_INTERACTIVE)
                {
                    callback = callbackInteractive;
                }
                else if (xhr.readyState == com.bristle.jslib.Ajax.Util.AJAX_STATE_LOADED)
                {
                    callback = callbackLoaded;
                }
                else if (xhr.readyState == com.bristle.jslib.Ajax.Util.AJAX_STATE_LOADING)
                {
                    callback = callbackLoading;
                }
                else if (xhr.readyState == com.bristle.jslib.Ajax.Util.AJAX_STATE_UNINITIALIZED)
                {
                    callback = callbackUninitialized;
                }
        
                // Call the callback.
                if (callback != null && typeof(callback) != "undefined")
                {
                    callback(xhr.responseXML, xhr);
                }
            }
        
            return timer;
        }

        --Fred

      3. Get XML via Ajax

        Original Version: 12/12/2007
        Last Updated: 12/13/2007
        Applies to:  JavaScript 1.0+, IE 5.5+, Firefox 1+, Netscape 7+

        The next step after creating the Ajax object and registering the callback function(s) is typically to call open() and send() and then wait for the callbacks to occur.  

        To simplify things even further, it makes sense to have a single routine that does it all, so Simple Ajax Example becomes a one-liner:

                com.bristle.jslib.Ajax.Util.getAjaxXML
        		("my_servlet?p1=abc"
                	,doSomethingWith
                	,null
                	,null
                	,null
                	,showProgressIndicator);

        or if you have more callbacks and a timeout:

        	com.bristle.jslib.Ajax.Util.getAjaxXML
        		(my_servlet?p1=abc"
        		,reportSuccess
        		,reportFailure
        		,10000  // 10 second timeout
        		,reportTimeout
        		);

        or specifying all possible callbacks and a timeout:

        	com.bristle.jslib.Ajax.Util.getAjaxXML
        		(my_servlet?p1=abc"
        		,reportSuccess
        		,reportFailure
        		,10000  // 10 second timeout
        		,reportTimeout
        		,reportInteractive
        		,reportLoaded
        		,reportLoading
        		,reportUninitialized
        		);

        Here is a Bristle Software JavaScript Library routine that does it:

        /******************************************************************************
        * Creates a new XMLHttpRequest object for use with Ajax operations, registers 
        * the specified functions as callbacks, and queues an asynchronous request to 
        * get XML from the specified URL.  The callback functions will be called 
        * asynchronously in response to the various state changes of the 
        * XMLHttpRequest as it processes the Ajax request.
        *
        * Notes:
        * - See registerAjaxCallbacksAndStartTimer for details of the callback 
        *   parameters, which are all optional.
        *
        *@param strURL              The URL to be accessed via Ajax
        *@param callbackSuccess     Function to be called when the state is Complete, 
        *                           and the HTTP status indicates success.
        *@param callbackFailure     Function to be called when the state is Complete, 
        *                           and the HTTP status indicates failure.
        *@param intTimeoutMillisecs Number of seconds before aborting the Ajax call
        *                           and calling callbackTimeout.
        *                           Optional.  Default=0 which means wait forever.
        *@param callbackTimeout     Function to be called if the Ajax call times out.
        *@param callbackInteractive Function to be called when the state is Interactive
        *@param callbackLoaded      Function to be called when the state is Loaded
        *@param callbackLoading     Function to be called when the state is Loading
        *@param callbackUninitialized
        *                           Function to be called when the state is Uninitialized
        *@throws com.bristle.jslib.Exception.intEXC_UNABLE_TO_CREATE_AJAX_OBJECT
        *@throws com.bristle.jslib.Exception.intEXC_ERROR_DURING_AJAX_OPEN
        *@throws com.bristle.jslib.Exception.intEXC_ERROR_DURING_AJAX_SEND
        ******************************************************************************/
        com.bristle.jslib.Ajax.Util.getAjaxXML =
        function(strURL
                ,callbackSuccess
                ,callbackFailure
                ,intTimeoutMillisecs
                ,callbackTimeout
                ,callbackInteractive
                ,callbackLoaded
                ,callbackLoading
                ,callbackUninitialized)
        {
        
            var xhr = com.bristle.jslib.Ajax.Util.createAjaxObject();
        
            // Try block to catch all errors so the timer can be cancelled.
            var timer = null;
            try
            {
                timer = com.bristle.jslib.Ajax.Util.registerAjaxCallbacksAndStartTimer
                    (xhr
                    ,callbackSuccess
                    ,callbackFailure
                    ,intTimeoutMillisecs
                    ,callbackTimeout
                    ,callbackInteractive
                    ,callbackLoaded
                    ,callbackLoading
                    ,callbackUninitialized
                    );
        
                // Queue the asynchronous HTTP request.
                try 
                {
                    var blnASYNC = true;
                    xhr.open("GET", strURL, blnASYNC);
                }
                catch (exception)
                {
                    throw new com.bristle.jslib.Exception.Exception
                            (com.bristle.jslib.Exception.intEXC_ERROR_DURING_AJAX_OPEN
                            ,"Error during open() of Ajax object"
                            ,"com.bristle.jslib.Ajax.Util.getAjaxXML"
                            );
                }
                try 
                {
                    xhr.send("");
                }
                catch (exception)
                {
                    throw new com.bristle.jslib.Exception.Exception
                            (com.bristle.jslib.Exception.intEXC_ERROR_DURING_AJAX_SEND
                            ,"Error during send() of Ajax object"
                            ,"com.bristle.jslib.Ajax.Util.getAjaxXML"
                            );
                }
            }
            catch (exception)
            {
                if (timer != null)
                {
                    window.clearTimeout(timer);
                }
                throw exception;
            }
        }

        --Fred

      4. Synchronous Ajax

        Original Version: 6/1/2008
        Last Updated: 6/1/2008
        Applies to:  JavaScript 1.0+, IE 5.5+, Firefox 1+, Netscape 7+

        Ajax is most commonly done asynchronously, so that the browser window doesn't freeze while waiting for the server.  However, for those times when you prefer simplicity, and can afford to briefly freeze the browser, synchronous Ajax is even easier.

        You can retrieve a string from the server, with a one-liner like:

                strData = com.bristle.jslib.Ajax.Util.doSynchronousAjax
                		('my_servlet?p1=abc').responseText;

        or to get an XML DOM that you can then manipulate:

                xmlDOM = com.bristle.jslib.Ajax.Util.doSynchronousAjax
                		('my_servlet?p1=abc').responseXML;

        or to check the success of the Ajax operation before manipulating the data:

                xhr = com.bristle.jslib.Ajax.Util.doSynchronousAjax
                		('my_servlet?p1=abc');
                if (xhr.status >= 200 && xhr.status <= 299)
                {
                    strData = com.bristle.jslib.Ajax.Util.doSynchronousAjax
                		('my_servlet?p1=abc').responseText;
                }
                else
                {
                    alert("Ajax error: " + xhr.status + ": " + xhr.statusText);
                }

         

        Here is a Bristle Software JavaScript Library routine that does it:

        /******************************************************************************
        * Creates a new XMLHttpRequest object and uses it synchronously to make an
        * HTTP request.
        *@param strURL              The URL to be accessed via Ajax
        *@return The XMLHttpRequest object, so the caller can examine its properties:
        *           status, statusText, responseText, responseXML
        *@throws com.bristle.jslib.Exception.intEXC_UNABLE_TO_CREATE_AJAX_OBJECT
        *@throws com.bristle.jslib.Exception.intEXC_ERROR_DURING_AJAX_OPEN
        *@throws com.bristle.jslib.Exception.intEXC_ERROR_DURING_AJAX_SEND
        ******************************************************************************/
        com.bristle.jslib.Ajax.Util.doSynchronousAjax =
        function(strURL)
        {
            var xhr = com.bristle.jslib.Ajax.Util.createAjaxObject();
            try 
            {
                var blnASYNC = true;
                xhr.open("GET", strURL, !blnASYNC);    //?? Change to POST?
            }
            catch (exception)
            {
                throw new com.bristle.jslib.Exception.Exception
                        (com.bristle.jslib.Exception.intEXC_ERROR_DURING_AJAX_OPEN
                        ,"Error during open() of Ajax object"
                        ,"com.bristle.jslib.Ajax.Util.doSynchronousAjax"
                        );
            }
            try 
            {
                xhr.send("");
            }
            catch (exception)
            {
                throw new com.bristle.jslib.Exception.Exception
                        (com.bristle.jslib.Exception.intEXC_ERROR_DURING_AJAX_SEND
                        ,"Error during send() of Ajax object"
                        ,"com.bristle.jslib.Ajax.Util.doSynchronousAjax"
                        );
            }
            return xhr;
        }

        --Fred

    6. Loading Images

      1. Set the SRC property of the IMG

        Last Updated: 6/3/2008
        Applies to:  All browsers

        Dynamically loading images into a Web page is even easier than loading XML or text.  Simply assign a new URL to the SRC property of the IMG tag, as:

        	document.getElementById("img1").src = "image1.jpg";

        or, if you are generating the images with a servlet: 

        	document.getElementById("img1").src = "my_servlet?p1=abc";

        This makes sense because browsers were invented in the days of slow Internet connections, where images took a long time to load, and impatient users often clicked ahead on partially loaded pages to go to the next page.  Therefore, image loading has always been done in a separate thread from the main page load, and has always been dynamic.  The same is true for the SRC property of the IFRAME and SCRIPT tags, so you can do pseudo-Ajax of text via them.

        However, there are some "gotchas" to be aware of.  See the tips below.

        --Fred

      2. Prevent Browser Image Caching

        Original Version: 6/3/2008
        Last Updated: 6/4/2008
        Applies to:  All browsers

        Beware browser caching when image files may change on the server, or when you are dynamically generating images with a servlet.  If the new URL is identical to a URL that is already in the browser cache, the browser may reuse the old image.  This can happen despite any Cache-Control HTTP header set by the servlet, and despite any non-caching options the user may have set in the browser.

        To force the browser to go back to the server for a new image, include a dummy URL parameter with a unique value.  Using a simple JavaScript counter may not be sufficient:

        	var intCounter = 1;
        	function myFunction()
        	{
        	    document.getElementById("img1").src = "my_servlet?p1=abc"
        	            + "&forceReload=" + (intCounter++);
        	}

        Even if intCounter is a global JavaScript variable, it gets reset at each page load, so you may still get duplicates.  It is better (and easier) to use a random number as: 

        	document.getElementById("img1").src = "my_servlet?p1=abc"
        	        + "&forceReload=" + Math.random();

        However, there's still the slight chance of getting duplicate random numbers eventually, so you could use the current time in milliseconds as: 

        	document.getElementById("img1").src = "my_servlet?p1=abc"
        	        + "&forceReload=" + new Date().getTime();

        However, there's still the slight chance of generating multiple URLs in the same millisecond, and JavaScript doesn't yet have an equivalent to Java's System.nanoTime().  Besides, some day computers will be fast enough that you'd need picoTime(), or femtoTime(), or attoTime(), or zeptoTime(), or yoctoTime(), or...

        In cases where it really matters, it's probably best to use both, since you're VERY unlikely to get the same random number twice in the same millisecond: 

        	document.getElementById("img1").src = "my_servlet?p1=abc"
        	        + "&forceReload=" + Math.random()
        	        + "_" + new Date().getTime();

        Personally, I wrap it all up and make it self-documenting as: 

        	document.getElementById("img1").src = "my_servlet?p1=abc"
        	        + com.bristle.jslib.Ajax.Util.getForceReloadParam();

        Here is the Bristle Software JavaScript Library routine to generate the random URL param:

        /******************************************************************************
        * Get a unique URL parameter to force a reload, bypassing any cached pages.
        ******************************************************************************/
        com.bristle.jslib.Ajax.Util.getForceReloadParam =
        function()
        {
            // Generate a unique URL param to force a reload, bypassing the browser
            // cache.  This is especially useful for loading images via the SRC 
            // property of the IMG tag because otherwise, depending on the browser
            // and the user settings, the previously cached image may be re-used, 
            // despite any Cache-Control header that may be set.
            // Note:  Use a timestamp to avoid random duplicates.
            // Note:  Use a random number in case of multiple calls within the same
            //        millisecond.
            // Note:  Use getTime(), not getMillseconds() which returns a value 0-999.
            intRandom = com.bristle.jslib.Util.randomInt(1,1000000);
            return "&forceReload=" + intRandom + "_" + new Date().getTime();
        }

        and the Bristle Software JavaScript Library routine that it calls internally:

        /******************************************************************************
        * Generate a random integer between the specified min and max.
        *
        *@param intMin  Min acceptable random integer (inclusive)
        *@param intMax  Max acceptable random integer (inclusive)
        *@return        The random number
        ******************************************************************************/
        com.bristle.jslib.Util.randomInt =
        function(intMin, intMax)
        {
            if ((typeof(intMin) == "undefined") || (intMin == null))
            {
                intMin = 0;
            }
            if ((typeof(intMax) == "undefined") || (intMax == null))
            {
                intMax = Math.pow(2, 16) - 1;
            }
        
                                                        // Example with min 6 and max 10:
            var intRangeSize = intMax - intMin + 1;     // Range size = 5
            var intRandom = Math.random();              // Between 0 and 0.999...
            intRandom *= intRangeSize;                  // Between 0 and 4.999...
            intRandom = Math.floor(intRandom);          // Between 0 and 4
            intRandom += intMin;                        // Between 6 and 10
            return intRandom;
        }

        Thanks to John Ferguson and Matt Brophy for pushing me to bother including the timestamp, not just a random number!

        --Fred

      3. Beware <IMG SRC="">

        Last Updated: 6/3/2008
        Applies to:  All browsers

        To avoid mysterious page re-loads and mysterious execution of server side code, don't use the empty string ("" or '') as the value of SRC.  Instead, use the URL of an invisible GIF file, like this one, which you can right-click to download:  invisible.gif.  

        If you are planning to dynamically update the URL of an image immediately, you may not care what value is specified in the static HTML and may be tempted to specify the empty string as:

        	<img id='img1' src=''>

        Bad idea!  Use an invisible GIF instead, as: 

        	<img id='img1' src='invisible.gif'>

        Similarly, if you want to dynamically clear the image, you may be tempted to specify the empty string as: 

        	document.getElementById("img1").src = "";

        Don't do it!  Use an invisible GIF instead, as:

        	document.getElementById("img1").src = "invisible.gif";

        or better yet, dynamically set the IMG to invisible, as described in Hiding/showing HTML elements.

        Why?  2 reasons:

        In standards-compliant browsers like Firefox, the empty string maps to the URL (minus POST params) of the current page.  In non-standards-compliant browsers like Internet Explorer, it maps to the directory portion of the URL of the current page, which the server probably maps to a default page or servlet.  In either case, there are two problems:

        1. The URL returns an HTML page, not an image, so the browser displays its broken link image.
        2. Your server side code is being unexpectedly executed without any POST parameters, and may do screwy things, like re-running the most recent database transaction, re-adding a value to a shopping cart, etc.

        For more details, see Section 13.2 "Including an image: the IMG element" of the HTML spec:
            http://www.w3.org/TR/html401/struct/objects.html#h-13.2
        which defines the value of SRC as a standard URI, and Section 4.4 "Same-Document Reference" of the URI spec:
            http://tools.ietf.org/html/rfc3986#section-4.4
        which says that an empty string URI refers to the URI of the enclosing base document.

        --Fred

    7. Using Ajax for a Keep-Alive

      Last Updated: 12/13/2007
      Applies to:  JavaScript 1.0+, IE 5.5+, Firefox 1+, Netscape 7+

      OK.  So now, you're writing very sophisticated Web apps, using Ajax to go back to the server as needed, and presenting a very responsive and dynamic user interface.  You've put a large chunk of your application into a single Web page that interacts extensively with the user and collects lots of data.  But...

      What happens if the user enters a bunch of data and then goes to lunch for an hour without saving first?  Or spends a long time interacting with the fancy JavaScript parts of your app that collect data but don't need the server and so don't use Ajax?  When the user finally clicks Save or OK, it fails because the server session has timed out.  You've actually made things worse by taking the load off of the server and doing more locally.  How to prevent the timeouts?

      You could simply make the timeouts much longer, or disable them entirely.  However, the timeouts exist for a good reason.  They allow the server to discard the sessions of users who really are done with your app, and have closed the browser or gone to another site.  Without the timeouts, your server would waste lots of resources, and eventually crash for lack of memory.  Better to leave the timeouts in place.

      A better solution is to keep the sessions alive only for users who still have a Web page of your app open.  You can do this easily with a timer doing Ajax "keep-alive" operations to the server.  Ideally, you could just add a one-liner like the following to the onload event handler of each of your Web pages:

      	com.bristle.jslib.Ajax.Util.schedulePeriodicKeepAlive
      		("my_keep_alive_servlet"
      		,300000  // Every 5 minutes
      		);

      This would invoke your servlet every 5 minutes, ignoring any data it sent back, as well as ignoring whether it succeeded, failed, or timed out.  That's all you really need to prevent the session timeout.

      If you also want to process the returned data, detect Ajax failures and timeouts, warn the user that the server (or your communications to it) seems to be down temporarily, etc., you need additional callbacks to handle that, and might use:

      	com.bristle.jslib.Ajax.Util.schedulePeriodicKeepAlive
      		("my_keep_alive_servlet"
      		,300000  // Send keep-alive every 5 minutes
      		,!com.bristle.jslib.Ajax.Util.blnDO_FIRST_KEEP_ALIVE_IMMEDIATELY
      		,callbackSuccess
      		,callbackFailure
      		,30000	// Timeout each keep-alive after 30 seconds
      		,callbackTimeout
      		);

      Here is a Bristle Software JavaScript Library routine that does it:

      /******************************************************************************
      * Use Ajax operations to access the specified URL periodically to keep the 
      * connection to the server from timing out.  The specified callback functions
      * will be called asynchronously when the Ajax operation succeeds or fails.
      *
      * Notes:
      * - See registerAjaxCallbacksAndStartTimer for details of the callback 
      *   parameters, which are all optional.
      *
      *@param strURL          The URL to be accessed via Ajax
      *@param intMillisecs    Number of milliseconds to wait between accesses.
      *@param blnNow          Access the URL now, before the first delay, if true.
      *@param callbackSuccess Function to be called when the state is Complete, 
      *                       and the HTTP status indicates success.
      *@param callbackFailure Function to be called when the state is Complete, 
      *                       and the HTTP status indicates failure.
      *@param intTimeoutMillisecs 
      *                       Number of seconds before aborting the Ajax call
      *                       and calling callbackTimeout.
      *                       Optional.  Default=0 which means wait forever.
      *@param callbackTimeout Function to be called if the Ajax call times out.
      ******************************************************************************/
      com.bristle.jslib.Ajax.Util.blnDO_FIRST_KEEP_ALIVE_IMMEDIATELY = true;
      com.bristle.jslib.Ajax.Util.schedulePeriodicKeepAlive =
      function(strURL
              ,intMillisecs
              ,blnNow
              ,callbackSuccess
              ,callbackFailure
              ,intTimeoutMillisecs
              ,callbackTimeout
              )
      {
          // Schedule the next call to this function via setTimeout.
          // Note: Can get setTimeout to pass the arguments on the scheduled call,
          //       without having to stringize them into a call string, by creating 
          //       an anonymous function (closure) that calls the desired function
          //       passing the arguments, which are known via the closure at the 
          //       time the anonymous function is generated.
          var timer = window.setTimeout
                  (function()