Thứ Năm, 3 tháng 12, 2009

Ajax login form

Bài này hướng dẫn các bạn viết 1 form login bằng Ajax. Mục tiêu không nhằm giới thiệu 1 ajax framework nào mà viết toàn bộ từ bước cơ bản nhất kỹ thuật Ajax để có thể hiểu sâu Ajax là gì.
1. Tạo form login

Code:

<body>
<!-- Include AJAX Framework -->
<script src="ajax/ajax_framework.js" language="javascript"></script>
<!-- Show Message for AJAX response -->
<div id="login_response"></div>
<div id="divForm">
<!-- Form: the action="javascript:login()"call the javascript function "login" into ajax_framework.js -->
<form action="javascript:login()" method="post">
<input name="email" type="text" id="emailLogin" value=""/>
<input name="psw" type="password" id="pswLogin" value=""/>
<input type="submit" name="Submit" value="Login"/>
</form>
</div>
</body>

Để ý thấy khi submit, ta dùng một JS function để khởi tạo lời gọi Ajax: login(). Bạn không tìm thấy đoạn JS cho login() ở đây vì tôi link với 1 file .js bên ngoài tên là ajax-framework.js.
2. Tạo file .js để viết code Ajax

Code:

/* ---------------------------- */
/* XMLHTTPRequest Enable */
/* ---------------------------- */
function createObject() {
var request_type;
var browser = navigator.appName;
if(browser == "Microsoft Internet Explorer"){
request_type = new ActiveXObject("Microsoft.XMLHTTP");
}else{
request_type = new XMLHttpRequest();
}
return request_type;
}
var http = createObject();
/* -------------------------- */
/* LOGIN */
/* -------------------------- */
/* Required: var nocache is a random number to add to request. This value solve an Internet Explorer cache issue */
var nocache = 0;
function login() {
// Optional: Show a waiting message in the layer with ID ajax_response
document.getElementById('login_response').innerHTML = "Loading..."
// Required: verify that all fileds is not empty. Use encodeURI() to solve some issues about character encoding.
var email = encodeURI(document.getElementById('emailLogin').value);
var psw = encodeURI(document.getElementById('pswLogin').value);
// Set te random number to add to URL request
nocache = Math.random();
// Pass the login variables like URL variable
http.open('get', 'login.php?email='+email+'&psw='+psw+'&nocache = '+nocache);
http.onreadystatechange = loginReply;
http.send(null);
}
function loginReply() {
if(http.readyState == 4){
var response = http.responseText;
alert(response);
if(response == '0'){
// if login fails
document.getElementById('login_response').innerHTML = 'Login failed! Verify user and password';
// else if login is ok show a message: "Welcome + the user name".
} else {
document.getElementById('login_response').innerHTML = 'Welcome '+response;
document.getElementById('divForm').style.display = 'none';
}
}
}

Tập trung vào hàm login(), công việc của chúng ta là lấy được dữ liệu nhậu của user thông qua JS, dùng document.getElementById() để tìm đúng textbox cần lấy giá trị.
Sau đó, ta tạo một chuỗi query string, có thêm một giá trị nocache là giá trị phát sinh random nhằm chống lại việc trình duyệt cache file login.php, không truyền về server.
Đối tượng http là một đối tượng XMLHTTPRequest, giúp ta gửi 1 request tới server, đối tượng này tạo ra bởi hàm CreateObject().
Đoạn lệnh mock up này giúp chúng ta biết khi nào nhận được kết quả từ server thì sẽ gọi tiếp hàm loginReply() để xử lý.
http.onreadystatechange = loginReply;
Sau khi đã đặt thông tin hàm xử lý (gọi là hàm CallBack) thì http.send() sẽ gửi thông tin cần xử lý tới server. Ở đây, chúng ta gửi tới 1 file chuyên xử lý lời gọi Ajax là login.php

3. Tạo file xử lý lời gọi Ajax
File login.php

Code:

<?php
if(isset($_GET['email']) && isset($_GET['psw'])){
$email = $_GET['email'];
$psw = $_GET['psw'];
if ($email=='hung5s@yahoo.com' && $psw == '123')
echo $email;
else
echo '0';
}
?>

Bạn thấy rằng việc xử lý này cốt trả về một giá trị (hãy coi nó như 1 hàm trả về giá trị) nên ta chỉ trả về giá trị qua lệnh echo và giá trị đó phải dễ xử lý như là 0 hay $email.
Tiếp theo, function loginReply() xử lý giá trị trả về để hiển thị kết quả.
Bài viết chỉ tới đây để đơn giản cho các bạn thử nghiệm. Reply tiếp theo sẽ phân tích sâu hơn bản chất của Ajax và về đối tượng XMLHttpRequest.

---

Viết tiếp ví dụ Ajax login form để chúng ta có khái niệm rõ hơn về một buzz word nổi đình nổi đám 2 năm nay clip_image001[14]
AJAX, viết tắt của Asynchronous JavaScript and XML có nghĩa là kỹ thuật lập trình xử dụng JavaScript làm ngôn ngữ, XML làm công cụ gửi nhận dữ liệu và cơ chế hoạt động gửi nhận dữ liệu là Không đồng bộ (Asynchronous).
Rứa thì chúng ta thấy rằng trong đống Ajax này chả có gì là PHP clip_image001[15]... hợp lý.
Trên thực tế, kỹ thuật lập trình này được sử dụng nhiều trước khi có 1 tên chuẩn AJAX. Bản chất nó đơn giản là để giải quếyt bài toán sau:
Tôi có 1 web page và một chức năng xử lý (vd là login) cần thực hiện ở server vì lý dó liên quan tới những resource ở server (như là database về user). Tuy nhiên, tôi lại không muốn user phải submit nguyên 1 trang web chỉ để xử lý 1 chức năng nho nhỏ trên trang đó. Vậy, tôi phải làm sao để:
1. Lấy được thông tin cần gửi về server, nhào nặn nó thế nào đó trước khi gửi (vd kiểm tra coi nó có nhập đầy đủ, đúng format,...)
2. Gửi đống thông tin cần xử lý về server mà không submit webpage
3. Nhận lại kết quả của server một cách âm thầm vì không biết lúc nào server mới trả kết quả về
4. Hiển thị kết quả đó trên webpage cho user.
Bạn thấy rằng có 1 đống việc phải làm trên webpage trong khi nó đang nằm ở browser của người dùng. Vậy thì chỉ có 1 cách để làm: Code bằng JavaScript (trước khi IE hay FireFox kịp nghĩ ra cái gì gì script khác nữa cho browser trong tương lai clip_image001[16]).
Có công cụ để viết lệnh, vấn đề tiếp theo là định dạng dữ liệu cần truyền là gì. Đương nhiên tới nay XML là "ngon" nhất cho những dữ liệu phức tạp. Còn dữ liệu đơn giản (như ví dụ login này) thì chỉ cần text là được.
Vấn đề cuối cùng: 1 đối tựơng JavaScript mà trình duyệt cung cấp để gửi yêu cầu về server mà không phải submit page. Công cụ này cũng phải biết được quá trình xử lý ở server là gì, lúc nào xong để còn cho biết mà tiếp tục xử lý result nhận được. Công cụ ta dùng ở đây là XmlHttpRequest.
Hãy xem lại đoạn code CreateObject() trong file .js ở trên. Vấn đề hơi rối rắm với anh nông dân chảnh choẹ Microsoft là anh này nhà quê mà hơi khác người, không dùng XmlHttpRequest của JS mà chơi 1 ActiveX có tên là Microsoft.XMLHTTP. Do vậy mà ai muốn dùng Ajax trên cả FireFox, IE thì đều phải có đoạn code CreateObject() ở trên.
Như vậy ta có đối tượng chuyên chở (The Transporter) như sau: http = CreateObject();
Tiếp theo là vấn đề gửi data lên server. Chuyện làm sao lấy data ra khỏi mấy cái textbox, ta không bàn ở đây vì nó rối cả bài Ajax lên.
Xem 3 lệnh sau:

Code:

http.open('get', 'login.php?email='+email+'&psw='+psw+'&nocache = '+nocache);
http.onreadystatechange = loginReply;
http.send(null);

1. Ta chuẩn bị gửi dữ liệu lên server qua lệnh open. Chú ý là đây chỉ là chuẩn bị, chưa gửi đi.
2. Ta phải chỉ ra hàm callback sẽ xử lý kết quả trả về
3. Thực sự bắt đầu việc gửi data và chờ nhận kết quả
Một khi đã gửi, bạn nên biết là hàm callback 'loginReply' sẽ bị gọi liên tục vô số lần cho tới khi nào kết quả đc server trả về cho webpage. Trong vô số lần bị gọi này, chỉ có 1 lần cần xử lý là khi dữ liệu đã về tới webpage. Ta tìm ra lần này dựa vào giá trị State của anh chàng transpoter:
http.readyState == 4  <<< xem hàm loginReply()
Cuối cùng, khi đã có dữ liệu, ta lấy nó ra qua thuộc tính responseText hoặc responseXML.
response = http.responseText;
Chú ý là kết quả trả về là toàn bộ nội dung 1 webpage, ở đây là nội dung của trang login.php. Vì thế bạn phải kiểm tra trang này để nội dung trả về như mong muốn. Cẩn thận với những đoạn code nằm ngoài <?php ?> vì nó sẽ bị trả về cho hàm CallBack luôn.
Cuối cùng, đã có dữ liệu trả về, ta xử lý và hiển thị kết quả. Đoạn code xử lý trong ví dụ dùng một kỹ thuật DHTML (hay JS + CSS) để dấu đi cái form login và hiện ra chữ welcome ...

Send data dùng POST

Trong ví dụ trên, nếu bạn để ý thì http.open dùng phương thức GET để gửi data về server. Đương nhiên webpage hoạt động "thầm lặng" nên bạn không bị lộ password trên thanh address bar. Nhưng nếu dùng 1 tool để tracing các HTTP request (FireFox có cung cấp) thì chắc chắn sẽ thấy.
Nhu cầu khác cần gửi data bằng Post là giả sử cái form của ta chứa một textarea cho phép user nhập vào 1 văn bản dài vô thiên ủng. GET không kham nổi data qúa dài nên ta phải dùng post.
Đây là đoạn code modify lại để dùng POST khi send data:

Code:

http.open('post', 'login.php?nocache = '+nocache);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded;charset=UTF-8;');
http.onreadystatechange = loginReply;
http.send('email='+email+'&psw='+psw);

Tôi vẫn để nocache trên query string vì browser căn cứ vào URL chứ không phải data để cache và xử lý request của user.
Chú ý là nếu muốn test, bạn phải vào sửa trang login.php thay _GET bằng _POST.

xin bổ sung cái readyState ở trên. Tại lúc đầu t đọc k hiểu cái readyState tại sao lại = 4 nên search google, cho kết quả như sau
State       Description
0   The request is not initialized
1   The request has been set up
2   The request has been sent
3   The request is in process
4   The request is complete