Php AJAX + Dojo
— print (last updated: Mar 10, 2009) print

Select font size:
Download the PhpAjax.zip archive. Install it into your default website folder and set it up as a NetBeans project as done in Php Basics. There are two parts to this project which are divided into two subfolders:
dojo/       AJAX-driven examples using Dojo
native/     AJAX-driven examples using JavaScript directly
Of most interest to us is the Dojo code.

AJAX is an acronym for Asynchronous Javascript And Xml. The most important point that AJAX is about using JavaScript to make asynchronous server-side calls and change the appearance of a page through client-side programming. As a result, much of the usual server-side programming activity due to page refreshes can be avoided.

Dojo Toolkit

Modern web applications often feature specialized effects accomplished by JavaScript code written using client-side toolkits. Writing in JavaScript directly tends to be quite tedious and error-prone. The JavaScript language, per se, lacks capabilities for modularity, sharing and testing. Errors are often difficult to track down and browser differences become prominent. The point about client-side toolkits is that they: As can be expected, there are quite a few such toolkits. One can choose among a long list such as Dojo, Prototype, MochiKit, Google Web Toolkit, AJILE, Echo, Ext, jQuery, ASP.NET AJAX, MooTools, qooxdoo, Rialto, Rico, Scriptaculous, SmartClient, Spry, Yahoo! UI Library, etc.

Installation

Minimally, Dojo consists of only one JavaScript file which can be downloaded from the Dojo Home Page. It can also be downloaded as a zipped file from the computer science web site:
dojo-release-1.3.2.zip
Extract the zip file getting the folder dojo-release-1.3.2.
    Windows   Linux (Ubuntu)    

Windows

Move and rename this folder to this (or something of your choosing):
C:\dojo-release-1.3.2
Next, we'll make an alias URL for this location. Edit the Apache configuration file, httpd.conf (from the Apache menu). Go to the end of the file and add these lines:
Alias /dojolib "C:\dojo-release-1.3.2"
<Directory "C:\dojo-release-1.3.2">
  Options FollowSymLinks
  AllowOverride None
  Order allow,deny
  Allow from all
</Directory>
Then restart Apache (from the menu).

Testing/Debugging

JavaScript used in any setting is a difficult language to debug. Fortunately there are some tools and techniques that make it possible. The points about Firebug and console logging mentioned below were derived from this document:
Dojo Debugging Tutorial

Firefox and Firebug

Use Firefox and install Firebug. Firefox's built-in debugger is the Error Console, which is often acceptable in itself. One accesses the error information through Tools Error Console.

The problem is that only JavaScript errors/warnings will show up in the Error Console, but much more detailed information is usually needed to debug AJAX-related programming. Firebug fills the gap. Once installed, access it by: Tools Firebug Open Firebug.

HTML visibility

To illustrate the point I'm trying to make, if use JavaScript to generate HTML code (as we'll do below) and you attempt to "see" the underlying code via View Page Source, you will discover that it's not shown. However you will be able to see this JavaScript-generated code through Firebug's HTML tab.

Alerts and console logging

Use JavaScript alert statements to print out information and pause the browser before continuing.

Often better than alerts is Firebug's console logging. In Firebug, click the Console tab. You first have to activate the console, but once activated you can see the output of the following statements each of which produces a different colorization effect in the logging:
  console.log("Here am I sitting in a tin can, far above the world.")
  console.debug("Take your protein pills and put your helmet on.")
  console.info("Now it's time to leave the capsule if you dare.")
  console.warn("Can you hear me Major Tom?")
  console.error("Your circuit's dead, there's something wrong!")
You need to remember to deactivate (comment out) the console logging statements when used without Firebug, but if you're using this in conjuction with Dojo, this initial loading will avoid errors:
<script type="text/javascript" src="/dojolib/dojo/dojo.js"
        djConfig="parseOnLoad: true, isDebug: true"></script>

JavaScript object property spelling

JavaScript's class creation is not declaration-based like Java or Php but is done completely "on the fly." This means that JavaScript permits you to add new members at will to almost any existing object. A downside of this feature is that most misspellings of a subobject will not generate an error, such as:
dojo.byId('myelt').innerHtml = "hello"
when you really meant:
dojo.byId('myelt').innerHTML = "hello"
If it appears that "nothing is happening when it should," this is often the source of the problem.

Testing the Php handlers independently

It is sometimes useful to test the Php server-side handlers "by hand", independently of their being called by a JavaScript activation. To do so, make sure that the handlers accept both GET and POST queries equally, regardless of their intended usage. Namely, define
$param = array_merge( $_GET, $_POST );
and then use $param['name'] instead of, say, $_POST['name']. Then pass the incoming date to the handler script via the query string into the browser command line. For example, assuming that xx and yy are the relevant incoming query parameters, try:
http://localhost/default/.../handlers/my-handler.php?xx=1&yy=2

JavaScript & AJAX

The JavaScript language shares much of the same syntax as the Java language minus the strong typing. Strings can be delimited by double or single quotes and there is only one numeric type (represented by a double).

Other than language details, the most significant difference with Java is that JavaScript is built in to the standard browsers in order program all the browser features according to the so-called Document Object Model (DOM). The DOM supports at its top level the window object, representing the entire browser. The subobjects of window are these: For example, the expression window.document refers to the document part of window object. In all cases, JavaScript permits the omission of the top-level "window." syntax and simply write "document" (and others).

Introducing JavaScript code into HTML

JavaScript code is typically made available through the script tags:
<script type="text/javascript">
<!--
  JavaScript code here
// -->
</script>
These lines make a browser which does not recognize JavaScript ignore the code between:
<!--
and
// -->
Alternatively, an external code file, say extern-code.js can be loaded with this script tag usage:
<script type="text/javascript" src="extern-code.js"></script>

Activation through JavaScript Events

Our JavaScript code of interest consists mostly of functions called by JavaScript events. For example, we can create a "generic" button which calls a JavaScript function as follows:
<input type="button" onclick="my_button_handler()" value="Press Me"/>
or
<button onclick="my_button_handler()">Press Me</button>
where the JavaScript code section contains:
function my_button_handler()
{
  // what to do when the button is pressed
}

Reading/Writing HTML elements from JavaScript

Within JavaScript code we need to be able to read and write data from the HTML elements. JavaScript provides a number of ways to obtain a DOM object for an HTML element, but perhaps the simplest and direct way is by assigning an id attribute to the element and obtaining an object for it with the function document.getElementById. For example, if we define:
<input type="text" id="tf" /> 
then, within JavaScript we can obtain an object representing this textfield with the statement:
var tf = document.getElementById( "tf" )
All the attributes of the original HTML element become available to the JavaScript code as subobjects. For example, to put "HELLO" into the textfield, we write:
tf.value = "HELLO"
Boolean attributes behave like boolean values in JavaScript. For example, if we have:
<input type="checkbox" id="cb" /> Some Checkbox
Then we can determine if this checkbox is checked with this code:
var cb = document.getElementById( "cb" )
if (cb.checked) {  ...  }

The innerHTML JavaScript subobject

A useful JavaScript subobject that does not correspond to an attribute is innerHTML. It represents the content between the start and end tags of an HTML element. For example if we have
<p id="output">*************</p>
then this JavaScript code replaces the paragraph's current content by Hello World.
var output = document.getElementById( "output" )
output.innerHTML = "Hello World"
This example illustrates simple JavaScript manipulation of HTML elements in which a selection list's value is displayed in an HTML span element.

show-choice.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Show Choice</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript"> <!-- function showChoice(){ var sel = document.getElementById("sel") var output = document.getElementById("output"); output.innerHTML = sel.value } // --> </script> </head> <body> <h3>Selection with JavaScript Display</h3> <select id="sel" onchange="showChoice()"> <option value="">--- choose ---</option> <option value="1">AA</option> <option value="2">BB</option> <option value="3">CC</option> <option value="4">DD</option> <option value="5">EE</option> </select> Selected value: <span id="output"></span> </body> </html>

The textarea value subobject

The textarea supports data entry using the value subobject despite the fact that value is not an attribute. For example if we have:
<textarea id="ta" rows="10" cols="40"></textarea> 
then, to place text within this textarea, we would use JavaScript code like this:
var ta = document.getElementById( "ta" )
ta.value = "Text placed\nwithin the textarea";
Because textarea has start and end tags, it also supports the innerHTML subobject, but this appears to be less reliable (at least for version 7 of Internet Explorer), and the assignment:
ta.innerHTML = "Text placed\nwithin the textarea";
may not respect the newline character!

AJAX call to a server-side program

The main point of AJAX is that we can use JavaScript to call server-side program and deliver the result(s) directly to HTML elements. The key idea is the existence of a so-called JavaScript Http Request object which can invoke a server-side activation. The definition of this object is browser-dependent and so a common way to create such an object is via a JavaScript function like this:
function GetXmlHttpObject() {
  var obj = null;
  if (window.XMLHttpRequest)
    obj = new XMLHttpRequest();
  else if (window.ActiveXObject) 
    obj = new ActiveXObject("Microsoft.XMLHTTP");
  return obj;
}
The usage for a simple GET-activated call might go as follows:
url = /* server-side program execution */
after = function() {
  /* what to do after server-side call has completed */
}
xmlHttp = GetXmlHttpObject();

xmlHttp.onreadystatechange = function() {
  if (xmlHttp.readyState != 4) return
  if (requestTimer != null) clearTimeout(requestTimer)
  if (xmlHttp.status != 200) {
    alert("server error")
	 return
  }
  after();
}

xmlHttp.open("GET", url, true)
xmlHttp.send(null)
The activation of the server-side url actually takes place in the last two lines:
xmlHttp.open("GET", url, true)
xmlHttp.send(null)
but the JavaScript after function, is used before this server-side call. This is the essence of the asynchronous behavior of AJAX activations: the after function is part of a callback of the xmlHttp object.

To clarify the asynchronous nature, the client-side JavaScript program activates the url and then "continues on" without waiting for the completion of the activation, and sometime later the after function takes effect.

Server Output, JSON & XML

In most cases we are interested in the data the server can retrieve for us. Assuming the global availability of the JavaScript Http Request object, xmlHttp, as indicated above, the server-side raw output is available to us as:
var data = xmlHttp.responseText
For simple output, this is sufficient; for structured output, there are two possible formats: JSON or XML.

JSON format

The JSON (JavaScript Object Notation) represents data as certain Java "object literals". For example:
{ x: 222, y: "hello" }                  -- an "object" with members x and y
[ 12, "hello", 15 ]                     -- an array
[ {x: 12, y: "aa"}, {x: 17, y: "bb"} ]  -- an array of objects
We can convert the JSON object into JavaScript directly using JavaScript's eval operation used like this:
var data = eval( "(" + xmlHttp.responseText + ")" );
After that, we can access data as a JavaScript object like this (respectively):
data.x, data.y                -- an "object" with members x and y
data[0], data[1], ...         -- an array
data[0].x, data[1].y          -- an array of objects
Both Java and JavaScript support a "comma at the end" of the last array element, e.g.
[ 12, "hello", 15 ]    is the same as    [ 12, "hello", 15, ]
However, Internet Explorer, at least is some versions, appears to put an extra null at the end of array in the latter case. So it's better to avoid the "comma at the end."

XML format

XML format is assumed to be well known. The server-side program must send XML format in the strictest sense. For example, this static Php program might be used to send a booklist:
<?php
header("Content-type: text/xml");
echo <<<END
<?xml version="1.0"?>
<booklist>
  <book>
    <title>Java Programming</title>
    <type>paper</type>
  </book>
  <book>
    <title>Perl Programming</title>
    <type>cloth</type>
  </book>
</booklist>
END;

This is precisely the situation where the Php "short open tag" will get you into trouble since it conflicts with the xml header tag. On the JavaScript side, you have to realize the data in a different way as:
var xmlData = xmlHttp.responseXML
Once you have data in this format, extracting the values is none too easy with code starting something like this:
var books = xmlData.getElementsByTagName("book");
and so on.

Prefer JSON to XML

It is more-or-less universally acknowleged that JSON format is better than XML for reasons both of efficiency and simplicity. In retrospect "AJAX" probably should have been "AJAJ"; however the former definitely sounds cooler.

Dojo Ajax Examples

The dojo folder illustrates AJAX-driven calls using the Dojo toolkit. The initial activation of Dojo is via the script usage:
<script type="text/javascript" src="/dojolib/dojo/dojo.js"
        djConfig="parseOnLoad:true"></script>
or else to ensure debugger handling:
<script type="text/javascript" src="/dojolib/dojo/dojo.js"
        djConfig="parseOnLoad: true, isDebug: true"></script>
After this, the global JavaScript object, dojo, is available for object-oriented calls. Our own example specific JavaScript file is then loaded via:
<script type="text/javascript" src="examples.js"></script>
This file uses dojo with member function calls like this GET activation of a URL
dojo.xhrGet(
  {
    url: "SERVER SIDE PROGRAM",
    content: { /* parameter: value pairs */ },
    load: function (response, ioArgs) {
      // this is activated after the server-side completion
      // response is the server output
    },
    error: function (response, ioArgs) {
      // what to do if something goes wrong, typically:
      alert("error: " + response)
    }
  }
)
The dojo.xhrGet function takes a single argument expressed as a JSON object. Here are some variations: One additional feature is the dojo.byId call as a convenient replacement of document.getElementById; e.g.,
  dojo.byId('the ID of some element').innerHTML = SOMETHING
Here is the code:

dojo/index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Dojo Examples</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="../my.css" type="text/css" /> <script type="text/javascript" src="/dojolib/dojo/dojo.js" djConfig="parseOnLoad:true"></script> <script type="text/javascript" src="examples.js"></script> <script type="text/javascript"> dojo.addOnLoad( // an alternative to using onload="..." in body function() { ex3_init() ex4_init() } ) </script> </head> <body> <a href="javascript:location.replace('..')">UP</a> <h3>Examples of usage of Dojo-AJAX</h3> <h4>Example 1: server-side script "get-time.php"</h4> <input type="submit" onclick="ex1_handler()" value="Get Times" /> <p> client-side time: <span id="ex1_c"></span> <br /> server-side time: <span id="ex1_s"></span> </p> <h4>Example 2: server-side script "get-book.php"</h4> <p>This transmission format is called JSON. </p> <table cellpadding="5px" border="1"> <tr><td>title:</td> <td id="title">&nbsp;</td></tr> <tr><td>type:</td> <td id="type">&nbsp;</td></tr> <tr><td>qty:</td> <td id="qty">&nbsp;</td></tr> </table> <p> <select id="id"> <option value="1">1</option> <option value="2">2</option> </select> <button onclick="ex2_set()">Get Book</button> </p> <h4>Example 3: server-side script "get-set-session-value.php"</h4> <p>Type values into both textfields. Click the button. <br /> Go UP and back here to observe the second value preserved. </p> <input type="text" /> <input type="text" id="ex3" /> <button onclick="ex3_set()">Save Second as Session "xx"</button> <h4>Example 4: server-side script "get-options.php"</h4> <p>The selection list is populated from JavaScript array of objects sent by the server-side script (JSON again). </p> <select id="ex4" onchange="ex4_set()"></select> Value: <span id="ex4_value"></span> <h4>Example 5: server-side script "show-post.php"</h4> <p> Dojo-AJAX presented more like a usual form submission.<br /> Enter data into the fields and press the button. </p> <form id="ex5_form" method="post"> <table cellpadding="5px"> <tr><td>title:</td> <td><input type="text" name="title"/></td></tr> <tr><td>type:</td> <td><input type="text" name="type"/></td></tr> <tr><td>qty:</td> <td ><input type="text" name="qty"/></td></tr> </table> <button onclick="ex5_handler();return false;"> Send Named Params </button> </form> <p> <textarea id="book_content" rows="8" cols="30" readonly></textarea> </p> </body> </html>

dojo/examples.js
function ex1_handler() { dojo.xhrGet( { url: "../handlers/get-time.php", load: function (response, ioArgs) { dojo.byId('ex1_s').innerHTML = response }, error: function (response, ioArgs) { alert("error: " + response) } } ) dojo.byId('ex1_c').innerHTML = new Date() } function ex2_set() { var id_val = dojo.byId("id").value dojo.xhrGet( { url: "../handlers/get-book.php", content: { id: id_val }, handleAs: "json", load: function(response, ioArgs) { dojo.byId("title").innerHTML = response.title; dojo.byId("type").innerHTML = response.type; dojo.byId("qty").innerHTML = response.qty; }, error: function (response, ioArgs) { alert("error: " + response) } } ) } function ex3_set() { var ex3_value = document.getElementById("ex3").value dojo.xhrGet( { url: "../handlers/get-set-session-xx.php", content: { xx: ex3_value }, error: function (response, ioArgs) { alert("error: " + response) } } ) } function ex3_init() { dojo.xhrGet( { url: "../handlers/get-set-session-xx.php", sync: true, load: function(response, ioArgs) { dojo.byId("ex3").value = response }, error: function (response, ioArgs) { alert("error: " + response) } } ) } // Example 4 also illustrates how the handler function can be // treated externally from the dojo.xhr call function display_options(response, ioArgs) { // response is an array of (value,label) objects // tack the intial ( no choice ) object on the front: // There is also a list.add function which seems more "Java-like", // but it may have to be used differently in different browsers var selections = [ {value: 0, label: "-----"} ].concat( response ); var list = dojo.byId("ex4"); for (i = 0; i < selections.length; ++i) { list.options[i] = new Option(selections[i].label, selections[i].value) } list.options[selections.length - 1].selected = true; } function ex4_init() { dojo.xhrGet( { url: "../handlers/get-options.php", handleAs: "json", sync: true, load: display_options, error: function (response, ioArgs) { alert("error: " + response) } } ) } function ex4_set() { dojo.byId("ex4_value").innerHTML = dojo.byId("ex4").value; } function ex5_handler() { dojo.xhrPost( { url: '../handlers/show-post.php', form: "ex5_form", load: function (response, ioArgs) { dojo.byId('book_content').value = response }, error: function (response, ioArgs) { alert("error: " + response) } } ) }
The server-side scripts used are these:

handlers/get-time.php
<?php sleep(1); echo date("r");

handlers/get-book.php
<?php $books = array( 1 => array("title" => "Java Swing", "type" => "paper", qty => 3 ), 2 => array("title" => "'Fun' with \"Quotes\"", "type" => "cloth", qty => 5 ), ); $id = $_GET['id']; ?> { title: "<?= htmlspecialchars($books[$id]['title']) ?>", type: "<?= htmlspecialchars($books[$id]['type']) ?>", qty: <?= $books[$id]['qty'] ?> }

handlers/get-set-session-xx.php
<?php session_start(); if (isset($_GET['xx'])) { $_SESSION['xx'] = $_GET['xx']; } echo $_SESSION['xx'];

handlers/get-options.php
[ { value: 1, label: "A" }, { value: 2, label: "B" }, { value: 3, label: "C" }, { value: 3, label: "D" } ]

handlers/show-post.php
<?php echo '$_POST: '; print_r($_POST);

Native Ajax Examples

The native folder illustrates AJAX-driven calls using plain JavaScript encapsulated in the JavaScript file ajax.js. This file provides two functions usable for making an AJAX activations:
ajaxGetCall(url, params, after)
ajaxPostCall(url, params, after)
The url paramater, in our case, will be a Php program; params is a string of encoded parameters of the form:
name1=value1&name2=value2&...
and after is a JavaScript function to be activated when the server-side script is complete. A function
urlEncode(str)
is a helper for creating the correct encoding.

The JavaScript Http Request object, xmlHttp, is a global variable and can therefore be used in the after function to obtain the server-side standard output as:
xmlHttp.responseText
Here are the sample files:

native/index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Native Examples</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="../my.css" type="text/css" /> <script type="text/javascript" src="ajax.js"></script> <script type="text/javascript" src="examples.js"></script> </head> <body onload="init()"> <a href="javascript:location.replace('..')">UP</a> <h3>Examples of native usage of AJAX</h3> <h4>Example 1: server-side script "get-time.php"</h4> <input type="submit" onclick="ex1_handler()" value="Get Times" /> <p> client-side time: <span id="ex1_c"></span> <br /> server-side time: <span id="ex1_s"></span> </p> <h4>Example 2: server-side script "get-book.php"</h4> <p> This transmission format is called JSON. </p> <table cellpadding="5px" border="1"> <tr><td>title:</td> <td id="title">&nbsp;</td></tr> <tr><td>type:</td> <td id="type">&nbsp;</td></tr> <tr><td>qty:</td> <td id="qty">&nbsp;</td></tr> </table> <p> <select id="id"> <option value="1">1</option> <option value="2">2</option> </select> <button onclick="ex2_set()">Get Book</button> </p> <h4>Example 3: server-side script "get-set-session-value.php"</h4> <p> Type values into both textfields. Click the button. <br /> Go UP and back here to observe the second value preserved. </p> <input type="text" /> <input type="text" id="ex3" /> <button onclick="ex3_set()">Save Second as Session "xx"</button> <h4>Example 4: server-side script "get-options.php"</h4> <p> The selection list is populated from JavaScript array of objects sent by the server-side script (JSON again). </p> <select id="ex4" onchange="ex4_set()"></select> Value: <span id="ex4_value"></span> </body> </html>

native/examples.js
function ex1_handler() { ajaxGet( "../handlers/get-time.php", null, function() { document.getElementById("ex1_s").innerHTML = xmlHttp.responseText } ) document.getElementById("ex1_c").innerHTML = new Date() } function ex2_set() { var id_val = document.getElementById("id").value ajaxGet( "../handlers/get-book.php", "id=" + id_val, function() { var data = eval( "(" + xmlHttp.responseText + ")" ) document.getElementById("title").innerHTML = data.title; document.getElementById("type").innerHTML = data.type; document.getElementById("qty").innerHTML = data.qty; } ) } function ex3_set() { var ex3_value = document.getElementById("ex3").value ajaxGet( "../handlers/get-set-session-xx.php", "xx=" + urlEncode(ex3_value), null ) } function ex4_set() { var list = document.getElementById("ex4"); var value_elt = document.getElementById("ex4_value"); value_elt.innerHTML = list.value; } function display_options() { var data = eval( "(" + xmlHttp.responseText + ")" ) var selections = [ {value: 0, label: "-----"} ].concat( data ); var list = document.getElementById("ex4"); for (i = 0; i < selections.length; ++i) { list.options[i] = new Option(selections[i].label, selections[i].value) } list.options[selections.length - 1].selected = true; } function list_init() { ajaxGet( "../handlers/get-options.php", null, display_options ) } /* One of the downsides of my "native" approach is the inability * to easily do two AJAX calls on one event. I have to force them * to be executed in sequence as is done here. */ function init() { ajaxGet( "../handlers/get-set-session-xx.php", null, function() { // initialize the ex2 textfield from session value document.getElementById("ex3").value = xmlHttp.responseText list_init(); // initialize the ex3 list } ) }

native/ajax.js
/* ajax.js * author: Robert Kline */ var xmlHttp function GetXmlHttpObject() { var obj = null; if (window.XMLHttpRequest) obj = new XMLHttpRequest(); else if (window.ActiveXObject) obj = new ActiveXObject("Microsoft.XMLHTTP"); return obj; } function ajaxGet(url, params, after) { xmlHttp = GetXmlHttpObject(); if (xmlHttp == null) return; var requestTimer xmlHttp.onreadystatechange = function() { if (xmlHttp.readyState != 4) return if (requestTimer != null) clearTimeout(requestTimer) if (xmlHttp.status != 200) { alert("server error") return } if (after != null) after(); } if (params != null) url += "?" + params requestTimer = setTimeout( function() { xmlHttp.abort(); alert("time out") }, 5000 ) xmlHttp.open("GET", url, true) xmlHttp.send(null) } function ajaxPost(url, params, after) { xmlHttp = GetXmlHttpObject(); if (xmlHttp == null) return; var requestTimer xmlHttp.onreadystatechange = function() { if (xmlHttp.readyState != 4) return if (requestTimer != null) clearTimeout(requestTimer) if (xmlHttp.status != 200) { alert("server error") return } if (after != null) after(); } if (params != null) url += "?" + params requestTimer = setTimeout( function() { xmlHttp.abort(); alert("time out") }, 5000 ) xmlHttp.open( "POST", url, true ); xmlHttp.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8' ) xmlHttp.send(params) } function urlEncode(str) { var newstr = escape(str); newstr = newstr.replace(/\+/g, "%2B"); newstr = newstr.replace(/\//g, "%2F"); return newstr; }


© Robert M. Kline