II. Chèn thêm Script
Một người sử dụng ít quan tâm đến kỹ thuật, chỉ thấy trang web như 1 sản phẩm ở giai đoạn cuối cùng, với hình ảnh, âm thanh, chữ nghĩa đầy màu sắc sinh động. Còn những người tạo web bằng các công cụ trực quan có thể biết đến trang web ở dạng thô, với các thẻ HTML, các đoạn script. Nhưng bạn, tìm hiểu sâu hơn, bạn sẽ thấy trang web còn thể hiện được ở dạng cây.
Đây là một hồ sơ HTML đơn giản và tuân theo đúng chuẩn DOM :
Hồ sơ này mang cấu trúc XML, với nút gốc là html. Các tag không có tag đóng thì có ký tự "/" ở cuối tag mở. Và như vậy, hồ sơ này có thể biểu diễn ở dạng cây tương tự như 1 hồ sơ XML :

Trong cây trên, các nút như title, span, được xem là nút thành phần - element node, các nút chứa text như "SN Labs - Append Script", "Hello", gọi là text node.
Bất kỳ lúc nào, bạn cũng có thể dùng các phương thức của XML DOM để tác động vào hồ sơ, thêm và xóa các nút.
Để tạo 1 nút thành phần, chúng ta dùng phương thức :
Để tạo 1 nút text, chúng ta dùng phương thức :
Các nút thành phần thường có nhiều thuộc tính, như IMG thì có thuộc tính src chỉ định nơi lưu trữ hình ảnh. SPAN có thuộc tính style định dạng kiểu dáng. Nếu bạn muốn nút tạo ra có các thuộc tính này, bạn chỉ đơn giản gán nó vào dưới dạng propertyName="value";
Sau khi tạo ra 1 nút, chúng ta có thể chèn thêm vào cây hồ sơ hiện thời bằng phương thức appenChild.
Script dưới đây sẽ tạo ra 1 thẻ DIV có chiều ngang 200px và chiều cao 40px;
nhuộm vàng nó :
thêm 1 câu chào :
nhét vào trong thẻ div vừa rồi :
và đặt vào hồ sơ HTML :
Đó là nền tảng cơ chế làm việc của phương pháp chèn dữ liệu dạng Script vào trang web mà chúng ta dựa trên đó để cập nhật động nội dung 1 webpage.
Java Script hiện diện trong trang web dưới dạng thẻ script. Nếu xem xét theo mô hình DOM thì script cũng giống như mọi nút thành phần mà bạn có thể chèn thêm vào hồ sơ HTML bất cứ lúc nào cần đến. Để tiện sử dụng, chúng ta xây dựng 1 hàm nhỏ :
Rất dễ hiểu, apps nhận tham số url là đường dẫn sẽ được phần tử script sắp nhúng vào sử dụng làm thuộc tính src.
Bây giờ chúng ta làm 1 ví dụ.
Các website cho phép đăng ký tài khoản thường có 1 chế độ gọi là Check availability để người đăng ký kiểm tra nhanh cái tên mà họ muốn sử dụng vào dịch vụ này đã được cấp phát cho một người nào khác trước đó hay chưa. Sau khi bạn nhập tên mình chọn vào 1 textBox, bạn có thể click trên 1 button, và trang đăng ký sẽ âm thầm gửi truy vấn đến server, truy cập cơ sở dữ liệu, tìm kiếm cái tên mà bạn nhập vào xem đã dùng đến chưa. Nếu chưa có ai dùng tên này, nó thông báo ".. is available", ngược lại, nó sẽ báo "...is not available" để bạn chọn 1 cái tên khác.
Nhiều site tiến bộ hơn, sẽ ghi nhận sự kiện blur trên textBox đó, và tự động tiến hành kiểm tra trong khi bạn tiếp tục hoàn tất biểu mẫu. Đó chính là ý nghĩa đích thực của "asynchronous" trong cụm từ AJAX.
Để làm điều tương tự, chúng ta tạo 1 form chứa 1 textBox nhập username và 1 nút gọi lệnh kiểm tra :
Thẻ div "msg" sẽ trình bày thông báo kết quả kiểm tra.
Hàm check() của chúng ta như sau :
check() trước tiên kiểm tra textBox có rỗng hay không, nếu chứa dữ liệu, nó gọi hàm apps để chèn vào 1 file Java Script, hay chính xác hơn là 1 file php với dữ liệu trả xuống dưới dạng content-type =text/javascript, vì 1 file JavaScript thì không nhận được các tham số GET, POST.
Bây giờ là trang check.php;
Ở đây, bạn có 1 cơ sở dữ liệu tên là System, với 1 bảng tblUser để quản lý người dùng. Trong bảng này phải có cột Username lưu trữ các tên sử dụng.
Bạn lưu ý khi lấy $_GET["username"] :
thì lúc này giá trị nhận được không phải từ trong trang đăng ký, mà từ 1 URL string của file check.php.
Dòng code thứ 3 :
bắt buộc trình duyệt xem xét tài liệu gửi xuống như 1 một file Java Script.
Do đó, bạn hãy quan tâm đến đoạn :
Về logic thì không có gì khó hiểu. Nếu trong database chưa có Username
$user, chúng ta gọi hàm gTxt để gán chuỗi '<?=$user?> is
available' vào msg. Và tương tự cho trường hợp $user đã bị người khác
đăng ký trước.
Nhưng điều thú vị là file script này được chèn trong 1 trang đã hoàn tất việc tải xuống. Vậy nếu bạn gọi check thêm một lần nữa thì sao ? Nghĩa là sẽ có thêm 1 file JavaScript nữa được chèn vào sau nó ? Đúng vậy. Nhưng trình duyệt luôn xử lý theo thứ tự ưu tiên tăng dần từ trên xuống dưới 1 cây hồ sơ HTML. Những thành phần tải sau, nằm dưới, sẽ được ưu tiên thực thi. Cũng như khi bạn nhiều lần gán giá trị cho 1 biến, nó sẽ chỉ nhận được giá trị cuối cùng :
b sẽ mang giá trị 10.
Hạn chế của việc sử dụng phương pháp này để cập nhật động cho 1 trang web là chỉ có thể sử dụng giao thức GET. Mà GET thì có nghĩa là lộ liễu, dưới 1000 ký tự...
Tuy vậy, Append script vẫn có những giá trị thiết thực, chẳng hạn với các trang có chèn bộ gõ chữ Việt. Không phải lúc nào người dùng cũng cần đến nên chúng ta không nhất thiết phải tải song song với trang mà chỉ nên load xuống khi người dùng yêu cầu, cũng tiết kiệm được vài chục KB chứ ít gì đâu :)
Demo :
http://lovepm.uni.cc/Examples/AJAX/AddScript/
* Các Username bên cột Registered thì đã tồn tại trong database.
Một người sử dụng ít quan tâm đến kỹ thuật, chỉ thấy trang web như 1 sản phẩm ở giai đoạn cuối cùng, với hình ảnh, âm thanh, chữ nghĩa đầy màu sắc sinh động. Còn những người tạo web bằng các công cụ trực quan có thể biết đến trang web ở dạng thô, với các thẻ HTML, các đoạn script. Nhưng bạn, tìm hiểu sâu hơn, bạn sẽ thấy trang web còn thể hiện được ở dạng cây.
Đây là một hồ sơ HTML đơn giản và tuân theo đúng chuẩn DOM :
<html> <head> <title>SN Labs - Append Script </title> </head> <body> <span id="msg">Hello</span> <img src="myimage.gif"/> </body> </html>
Hồ sơ này mang cấu trúc XML, với nút gốc là html. Các tag không có tag đóng thì có ký tự "/" ở cuối tag mở. Và như vậy, hồ sơ này có thể biểu diễn ở dạng cây tương tự như 1 hồ sơ XML :

Trong cây trên, các nút như title, span, được xem là nút thành phần - element node, các nút chứa text như "SN Labs - Append Script", "Hello", gọi là text node.
Bất kỳ lúc nào, bạn cũng có thể dùng các phương thức của XML DOM để tác động vào hồ sơ, thêm và xóa các nút.
Để tạo 1 nút thành phần, chúng ta dùng phương thức :
document.createElement(nodeName);
Để tạo 1 nút text, chúng ta dùng phương thức :
document.createTextNode(text);
Các nút thành phần thường có nhiều thuộc tính, như IMG thì có thuộc tính src chỉ định nơi lưu trữ hình ảnh. SPAN có thuộc tính style định dạng kiểu dáng. Nếu bạn muốn nút tạo ra có các thuộc tính này, bạn chỉ đơn giản gán nó vào dưới dạng propertyName="value";
Sau khi tạo ra 1 nút, chúng ta có thể chèn thêm vào cây hồ sơ hiện thời bằng phương thức appenChild.
Script dưới đây sẽ tạo ra 1 thẻ DIV có chiều ngang 200px và chiều cao 40px;
oDiv=document.createElement("div"); oDiv.style.width="200px"; oDiv.style.height="40px";
nhuộm vàng nó :
oDiv.style.backgroundColor="#ffff55";
thêm 1 câu chào :
txt=document.createTextNode("Chào quý vị !");
nhét vào trong thẻ div vừa rồi :
oDiv.appendChild(txt);
và đặt vào hồ sơ HTML :
document.body.appendChild(oDiv);
Đó là nền tảng cơ chế làm việc của phương pháp chèn dữ liệu dạng Script vào trang web mà chúng ta dựa trên đó để cập nhật động nội dung 1 webpage.
Java Script hiện diện trong trang web dưới dạng thẻ script. Nếu xem xét theo mô hình DOM thì script cũng giống như mọi nút thành phần mà bạn có thể chèn thêm vào hồ sơ HTML bất cứ lúc nào cần đến. Để tiện sử dụng, chúng ta xây dựng 1 hàm nhỏ :
function apps(url){ var oScript = document.createElement("script"); oScript.src = url; document.body.appendChild(oScript); }
Rất dễ hiểu, apps nhận tham số url là đường dẫn sẽ được phần tử script sắp nhúng vào sử dụng làm thuộc tính src.
Bây giờ chúng ta làm 1 ví dụ.
Các website cho phép đăng ký tài khoản thường có 1 chế độ gọi là Check availability để người đăng ký kiểm tra nhanh cái tên mà họ muốn sử dụng vào dịch vụ này đã được cấp phát cho một người nào khác trước đó hay chưa. Sau khi bạn nhập tên mình chọn vào 1 textBox, bạn có thể click trên 1 button, và trang đăng ký sẽ âm thầm gửi truy vấn đến server, truy cập cơ sở dữ liệu, tìm kiếm cái tên mà bạn nhập vào xem đã dùng đến chưa. Nếu chưa có ai dùng tên này, nó thông báo ".. is available", ngược lại, nó sẽ báo "...is not available" để bạn chọn 1 cái tên khác.
Nhiều site tiến bộ hơn, sẽ ghi nhận sự kiện blur trên textBox đó, và tự động tiến hành kiểm tra trong khi bạn tiếp tục hoàn tất biểu mẫu. Đó chính là ý nghĩa đích thực của "asynchronous" trong cụm từ AJAX.
Để làm điều tương tự, chúng ta tạo 1 form chứa 1 textBox nhập username và 1 nút gọi lệnh kiểm tra :
Desired Login Name :<br> <form name="reg"> <input name="username" value="" type="text"><br> <input value="Check availability" onclick="check();" type="button"><br> <div id="msg"></div> </form>
Thẻ div "msg" sẽ trình bày thông báo kết quả kiểm tra.
Hàm check() của chúng ta như sau :
function check(){ var u=document.reg.username.value; if(u!=""){ apps('check.php?username='+u); } }
check() trước tiên kiểm tra textBox có rỗng hay không, nếu chứa dữ liệu, nó gọi hàm apps để chèn vào 1 file Java Script, hay chính xác hơn là 1 file php với dữ liệu trả xuống dưới dạng content-type =text/javascript, vì 1 file JavaScript thì không nhận được các tham số GET, POST.
Bây giờ là trang check.php;
<?php header("Cache-Control: no-cache, must-revalidate"); header("Content-type: text/javascript"); $user=addslashes($_GET["username"]); if($user!=""){ //giả định đầu tiên là chưa ai dùng cái username này $exist=false; $sql="Select * FROM tblUser WHERE Username='".$user."'"; // Mở kết nối với database $conn = mysql_connect("localhost","root",""); if(!$conn){ die('Could not connect database in this time ! '); exit(); } // chọn cơ sở dữ liệu System : mysql_select_db("System", $conn); // Thực thi truy vấn : $result = mysql_query($sql); // Nếu có mẩu tin , nghĩa là tên đã được dùng : if(mysql_num_rows($result)>0){ $exist=true; } mysql_free_result($result); mysql_close($conn); if(!$exist){ ?> gTxt('msg','<?=$user?> is available'); <? } else{ ?> gTxt('msg','<?=$user?> is not available'); <? } } ?>
Ở đây, bạn có 1 cơ sở dữ liệu tên là System, với 1 bảng tblUser để quản lý người dùng. Trong bảng này phải có cột Username lưu trữ các tên sử dụng.
Bạn lưu ý khi lấy $_GET["username"] :
$user=addslashes($_GET["username"]);
thì lúc này giá trị nhận được không phải từ trong trang đăng ký, mà từ 1 URL string của file check.php.
Dòng code thứ 3 :
header("Content-type: text/javascript");
bắt buộc trình duyệt xem xét tài liệu gửi xuống như 1 một file Java Script.
Do đó, bạn hãy quan tâm đến đoạn :
if(!$exist){ ?> gTxt('msg','<?=$user?> is available'); <? } else{ ?> gTxt('msg','<?=$user?> is not available'); <? }
Về logic thì không có gì khó hiểu. Nếu trong database chưa có Username
$user, chúng ta gọi hàm gTxt để gán chuỗi '<?=$user?> is
available' vào msg. Và tương tự cho trường hợp $user đã bị người khác
đăng ký trước.
Nhưng điều thú vị là file script này được chèn trong 1 trang đã hoàn tất việc tải xuống. Vậy nếu bạn gọi check thêm một lần nữa thì sao ? Nghĩa là sẽ có thêm 1 file JavaScript nữa được chèn vào sau nó ? Đúng vậy. Nhưng trình duyệt luôn xử lý theo thứ tự ưu tiên tăng dần từ trên xuống dưới 1 cây hồ sơ HTML. Những thành phần tải sau, nằm dưới, sẽ được ưu tiên thực thi. Cũng như khi bạn nhiều lần gán giá trị cho 1 biến, nó sẽ chỉ nhận được giá trị cuối cùng :
var a=4; a=15; a=9; b=a+1;
b sẽ mang giá trị 10.
Hạn chế của việc sử dụng phương pháp này để cập nhật động cho 1 trang web là chỉ có thể sử dụng giao thức GET. Mà GET thì có nghĩa là lộ liễu, dưới 1000 ký tự...
Tuy vậy, Append script vẫn có những giá trị thiết thực, chẳng hạn với các trang có chèn bộ gõ chữ Việt. Không phải lúc nào người dùng cũng cần đến nên chúng ta không nhất thiết phải tải song song với trang mà chỉ nên load xuống khi người dùng yêu cầu, cũng tiết kiệm được vài chục KB chứ ít gì đâu :)
Demo :
http://lovepm.uni.cc/Examples/AJAX/AddScript/
* Các Username bên cột Registered thì đã tồn tại trong database.