Skip to content


Cross Browser XMLHttpRequest

I recently did a lot of investigating around the best way to create an XMLHttpRequest, as various resources on the web use slightly different methods. Newer browsers (Chrome, Firefox, IE7+, Opera, and Safari) all have a native XMLHttpRequest object, so the exception is really IE versions less than 7.

Internet Explorer 5, 5.5, and 6 all support XMLHttpRequest by means of an ActiveXObject. But there are various versions of MSXML, and it was not clear to me which versions should be used, and in which order they should be declared. Microsoft recommended some versions, but their recommendation was 3 years old and I wasn’t sure if it was still applicable (or applicable at all when using MSXML for creating XMLHTTP objects). It turns out that it was.

Initially I wanted to support the widest range of browsers, including IE5 and IE5.5. However, those versions of IE are no longer supported by Microsoft, so why should I try and support them? I have no way to test in those versions. More research suggested that IE5 and IE5.5 account for only about .02% of browser market share (2 people out of 10,000) from August 2009 - October 2009. It doesn’t make sense to try and support IE5.x, which means there is no need to support the legacy Microsoft.XMLHTTP ActiveXObject.

That just leaves IE6. IE6 still has considerable market share, so I do want to support it. IE6 shipped with MSXML 3.0, which is the “fallback” version to use recommended by Microsoft. Previous versions of MSXML are no longer supported by Microsoft, so MSXML 3.0 will be my fallback version. The recommended version is MSXML 6.0 (note, it is NOT recommended to use MSXML 5.0 or MSXML 4.0).

So now I’m going to be working with a set of 3 possible objects:

  1. a native XMLHttpRequest object
  2. an MSXML 6.0 XMLHTTP ActiveXObject (IE6 only)
  3. an MSXML 3.0 XMLHTTP ActiveXObject (IE6 only, when MSXML 6.0 not available)

To see how I decided to format that code, visit:
http://www.webmasterworld.com/javascript/4027629.htm

Posted in AJAX, General, Web Development. Tagged with , , , .

Dependent Lists and Progressive Enhancement

I recently stumbled across a newsgroup post where someone needed dependent list boxes that let users select a car make from one list box and a second list box would be populated with car models. He wanted to use AJAX to get the list of models from the server, but also wanted a solution that would work for users that didn’t have JavaScript (particularly, mobile device users). My suggestion was to use progressive enhancement. The end result can be viewed at http://www.fotiweb.com/samples/dependent-list-box/, though some of this solution is PHP based (see below for that code).

My suggestion was to create a web service that would take a car make and return a list of models. He could interact with this service via an AJAX call, parse the results, and populate the list box with the results. Alternatively, his server side processing could determine if a make had been selected, and if so call the service to get the list and populate the list box that way.

I started by creating a basic HTML form:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
 "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
<style type="text/css">
select {
    width: 15em;
}
<title>Untitled</title>
<body>
</body> </html>

I used placeholders where the list options will be.

Next, I created the web service at . Here’s what that service looks like:

<?php
// This example returns just a simple comma separated list.
// A real world example would probably look up values from a
// database and might return a JSON or XML string with the
// results. This is just a proof of concept.
if (!isset($_GET['make'])) {
    // Exit nicely
    exit(0);
}
$make = $_GET['make'];
switch ($make) {
    case 'Ford':
        echo 'Focus,Explorer';
        break;
    case 'Nissan':
        echo 'Sentra';
        break;
    case 'Toyota':
        echo 'Prius,Tundra';
        break;
    default:
        echo '';
        break;
}
exit(0);
?>

Next I needed to create the PHP behind my form page. This PHP populates the vehicle makes and if the user has selected a make and clicked the “Get Models” button, will also populate the models by making a curl request to the web service.

<?php
// The 'makes' list might be populated from a database
$makes = array('Ford', 'Nissan', 'Toyota');
// 'models'
$models = array();
// 'selectedMake' The make selected by the user (if any)
$selectedMake = '';

// Check whether the make has been submitted
if (array_key_exists('getmodels', $_GET)) {
    if ( isset($_GET['make']) ) {
        $selectedMake = $_GET['make'];
        // Request model values for the selected
        $ch = curl_init("http://www.fotiweb.com/samples/dependent-list-box/getModels/?make=$selectedMake");
        // Return the transfer as a string
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        // $output contains the output string
        $models = curl_exec($ch);
        // Close the curl resource
        curl_close($ch);
        // Convert results to array
        $models = explode(',', $models);
    }
}

// Format variables for HTML output
$makeOptionList = '';
$modelsOptionList = '';

// Generate the options list of makes
foreach ($makes as $make) {
    $makeOptionList .= "<option value='$make'";
    if ($selectedMake == $make) {
        $makeOptionList .= " selected='selected'";
    }
    $makeOptionList .= ">$make</option>";
}

// Generate the options list of models
if (count($models) > 0) {
    foreach ($models as $model) {
        $modelsOptionList .= "<option value='$model'>$model</option>";
    }
}
else {
    $modelsOptionList = '<option value="">Select a Make</option>';
}
?>

So now the page is functioning for all users that don’t have JavaScript. When the page loads, the makes will be populated. If the user clicks on the “Get Models” button, the selected make will be submitted back to the PHP above, which in turn will populate the models and show the form again, but this time with the populated results.

All that’s left is to use Progressive Enhancement to provide an AJAX alternative to the post back to the server. An AJAX solution will be more responsive, as the entire page doesn’t need to be reloaded. Here’s the JavaScript code. Note, I’m using the Yahoo UI Library for it’s DOM manipulation, Event handling utility, Element manipulation, and Connection Manager for it’s simplified AJAX interface.


And then my own script:

var make = new YAHOO.util.Element('make'),
    submitbtn = new YAHOO.util.Element('getmodels'),
    models = new YAHOO.util.Element('models');

// Remove the submit button
submitbtn.setStyle('display','none');

// Attach event listeners to 'make' that will call getModels
// service, parse the results, and populate 'models' options
make.on('click', function (e) {
    YAHOO.util.Connect.setForm('getMakeModel');
    var transaction = YAHOO.util.Connect.asyncRequest('GET',
            'http://www.fotiweb.com/samples/dependent-list-box/getModels/', {
                success: function(o) {
                    var i, op, old,
                        modelList = o.responseText;
                    // Remove the existing option elements
                    old = models.getElementsByTagName('option');
                    while (old.length > 0) {
                        old[old.length - 1].parentNode.removeChild(old[old.length - 1]);
                    }
                    // Convert results to array
                    modelList = modelList.split(",");
                    // Generate the options list of models
                    for (i = 0; i < modelList.length; i++) {
                        op = document.createElement('option');
                        op.text = modelList[i];
                        op.value = modelList[i];
                        models.appendChild(op);
                    }
                }
    }, null);
});

This will hide the submit button and perform the request to the getModels service when the user selects a make. This is just one way you could use Progressive Enhancement to enhance your dependent lists.

Posted in Web Development. Tagged with .

Another Baby First

Today my son Alex waved “bye bye” to someone for the first time. I was surprised at how exciting I found it. He’s growing up so quick.

Posted in General.

Google Chrome

When I started heavily using Google apps like GMail, Calendar, and Documents, I decided to try out Google’s Chrome browser. It still has some bugs, but overall I have been very impressed with it.

Posted in General. Tagged with , , , , .