Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ajax In Action (2006).pdf
Скачиваний:
63
Добавлен:
17.08.2013
Размер:
8.36 Mб
Скачать

Writing to the server

193

 

 

response is interpreted purely as visual markup typically affecting a single rectangular region of the visible UI. XSLT is discussed in more detail in chapter 11.

Problems and limitations

The main limitation of a data-centric approach is that it places the burden of parsing the data squarely on the client. Hence the client-tier code will tend to be more complicated, but, where this approach is adopted wholesale in a larger application, the costs can be offset by reusing parser code or abstracting some of the functionality into a library.

The three approaches that we have presented here arguably form a spectrum between the traditional web-app model and the desktop-style thick client. Fortunately, the three patterns are not mutually exclusive and may all be used in the same application.

Client/server communications run both ways, of course. We’ll wrap up this chapter with a look at how the client can send data to the server.

5.5 Writing to the server

So far, we’ve concentrated on one side of the conversation, namely, the server telling the client what is going on. In most applications, the user will want to manipulate the domain model as well as look at it. In a multiuser environment, we also want to receive updates on changes that other users have made.

Let’s consider the case of updating changes that we have made first. Technically, there are two main mechanisms for submitting data: HTML forms and the XMLHttpRequest object. Let’s run through each briefly in turn.

5.5.1Using HTML forms

In a classic web application, HTML form elements are the standard mechanism for user input of data. Form elements can be declared in the HTML markup for a page:

<form method="POST" action="myFormHandlerURL.php"> <input type="text" name="username"/>

<input type="password" name="password"/> <input type="submit" value="login"/>

</form>

This will render itself as a couple of blank text boxes. If I enter values of dave and letmein on the form, then an HTTP POST request is sent to myFormHandlerURL.php, with body text of username=dave&password=letmein. In most modern web programming systems, we don’t directly see this encoded form

194CHAPTER 5

The role of the server

data but have the name-value pairs decoded for us as an associative array or “magic” variables.

It’s fairly common practice these days to add a little JavaScript to validate the form contents locally before submitting. We can modify our simple form to do this:

<form id="myForm" method="POST" action="" onsubmit="validateForm(); return false;">

<input type="text" name="username"/> <input type="password" name="password"/> <input type="submit" value="login"/>

</form>

And we can define a validation routine in the JavaScript for the page:

function validateForm(){

var form=document.getElementById('myForm'); var user=form.elements[0].value;

var pwd=form.elements[1].value;

if (user && user.length>0 && pwd && pwd.length>0){ form.action='myFormHandlerURL.php'; form.submit();

}else{

alert("please fill in your credentials before logging in");

}

}

The form is initially defined with no action attribute. The real URL is substituted only when the values in the form have been validated correctly. JavaScript can also be used to enhance forms by disabling the Submit button to prevent multiple submissions, encrypting passwords before sending them over the network, and so on. These techniques are well documented elsewhere, and we won’t go into them in depth here. Chapters 9 and 10 contain more detailed working examples of Ajax-enhanced HTML forms.

We can also construct a form element programmatically and submit it behind the scenes. If we style it to not be displayed, we can do so without it ever being seen by the user, as illustrated in listing 5.11.

Listing 5.11 submitData() function

function addParam(form,key,value){

var input=document.createElement("input"); input.name=key;

input.value=value;

form.appendChild(input);

}

Writing to the server

195

 

 

function submitData(url,data){

var form=document.createElement("form"); form.action=url;

form.method="POST"; for (var i in data){

addParam(form,i,data[i]);

}

form.style.display="none";

document.body.appendChild(form);

form.submit();

}

submitData() creates the form element and iterates over the data, adding to the form using the addParam() function. We can invoke it like this:

submitData(

"myFormHandlerURL.php",

{username:"dave",password:"letmein"}

);

This technique is concise but has a significant drawback in that there is no easy way of capturing a server response. We could point the form at an invisible IFrame and then parse the result, but this is rather cumbersome at best. Fortunately, we can achieve the same effect by using the XMLHttpRequest object.

5.5.2Using the XMLHttpRequest object

We’ve already seen the XMLHttpRequest object in action in chapter 2 and earlier in this chapter. The differences between reading and updating are minor from the client code’s point of view. We simply need to specify the POST method and pass in our form parameters.

Listing 5.12 shows the main code for our ContentLoader object developed in section 3.1. We have refactored it to allow parameters to be passed to the request, and any HTTP method to be specified.

Listing 5.12 ContentLoader object

net.ContentLoader=function

b Extra arguments

(url,onload,onerror,method,params,contentType){

this.onload=onload;

this.onerror=(onerror) ? onerror : this.defaultError; this.loadXMLDoc(url,method,params,contentType);

}

net.ContentLoader.prototype.loadXMLDoc

196CHAPTER 5

The role of the server

=function(url,method,params,contentType){ if (!method){

method="GET";

}

if (!contentType && method=="POST"){ contentType="application/x-www-form-urlencoded";

}

if (window.XMLHttpRequest){ this.req=new XMLHttpRequest();

} else if (window.ActiveXObject){

this.req=new ActiveXObject("Microsoft.XMLHTTP");

}

if (this.req){ try{

this.req.onreadystatechange=net.ContentLoader.onReadyState;

this.req.open(method,url,true);

 

 

 

HTTP method

 

 

 

if (contentType){

 

 

 

Content type

 

 

 

this.req.setRequestHeader("Content-Type", contentType);

}

 

Request parameters

this.req.send(params);

 

 

}catch (err){ this.onerror.call(this);

}

}

}

We pass in several new arguments to the constructor b. Only the URL (corresponding to the form action) and the onload handler are required, but the HTTP method, request parameters, and content type may be specified, too. Note that if we’re submitting key-value pairs of data by POST, then the content type must be set to application/x-www-form-urlencoded. We handle this automatically if no content type is specified. The HTTP method is specified in the open() method of XMLHttpRequest, and the params in the send() method. Thus, a call like this

var loader=net.ContentLoader( 'myFormHandlerURL.php', showResponse,

null,

'POST',

'username=dave&password=letmein'

);

will perform the same request as the forms-based submitData() method in listing 5.11. Note that the parameters are passed as a string object using the form-encoded style seen in URL querystrings, for example:

name=dave&job=book&work=Ajax_In+Action