Ajaxの実装 (検索サジェスト)
目標
本記事の目標は、以下のようにAjax通信による検索サジェストを実装することです。
環境

Ajaxについて
AJAX(Asynchronous JavaScript And XML)は、JavaScriptを使って、クライアント側で非同期通信を実現するためのWeb開発技術群を指す言葉です。非同期通信とAjaxについては、“AJAXとは (そして非同期通信とは)?”に詳しく記載しています。以下では、Ajaxの仕組みについて簡単に説明しています。
Ajaxの仕組み
Ajaxでは、「サーバーへのリクエスト送信と受信」「送信、受信した内容をブラウザ側に伝える」という2つの機構を分離しています。そのため、リクエスト待ちの間も、ブラウザ上で操作を続けることができます。

Ajaxにおいて、サーバーとクライアントの間を取り持ち、やりとりを管理する機構をAjaxエンジンと呼びます。
方法
Ajaxにおけるデータフロー
XMLHttpRequest()オブジェクトが、HTTPリクエストを送信し、レスポンスの受信を検知して、レスポンスを反映させます。
1. ブラウザのUIで、データ更新の要求を受け取る。

2. JavaScriptでXMLHttpRequest()オブジェクトを作成し、通信の完了を検知できるようにする。通信完了時の処理も先に設定。

3. XMLHttpRequest()を使ってHTTPリクエストを送信

4. レスポンスとしてXMLやJsonを受け取る

5. 受け取ったデータをブラウザ上に反映

Ajaxの実装
データベースは、“XAMPPでMaria DBのデータベースを作る”の手順に沿って作成しました。この程度のサイズであれば、先に全て取得した方が簡単なのですが、実際は大規模なデータベースがあると想定します。
データベース名: profile
テーブル名: user カラム(id, name, age, icon)

1. 検索フォームの作成
<form><input></input></form>タグで、検索フォームを作成します。

index.php
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>test</title> </head> <body> <form action=""> <label>Name:</label> <input id="input-area" type="text" name="word" list="name-list" autocomplete="off" /><input type="submit" value="Search" /> <datalist id="name-list"> </datalist> </form> </body> </html>
本来は、submit時に何らかのmehod(POST, GETなど)を実行し、ページ遷移をして結果を表示しますが、今回は検索サジェストの部分のみ作成します。
<datalist></datalist>に要素を追加することで、サジェストを表示します。
2. JavaScriptでXMLHttpRequest()オブジェクトを作成、リクエストを送信
index.php 内
<script> var input_area = document.getElementById('input-area') input_area.addEventListener("input", search); function search(){ var ajax = new XMLHttpRequest(); var word = input_area.value; ajax.open('GET', 'search.php?q='+ word); ajax.onreadystatechange = function(){ if(ajax.readyState == 4){ var suggest = document.getElementById("name-list"); var result_json_str = ajax.responseText; var name_list_tags = ""; if(result_json_str != ""){ var result_json_obj = JSON.parse(result_json_str); for(k in result_json_obj){ // get keys var item = result_json_obj[k]; name_list_tags += '<option value="' + item['name'] + '">'; } } suggest.innerHTML = name_list_tags; } } ajax.send(); } </script>
以下は、上記コードの詳細です。
inputに値が入力(削除)された際に、関数searchを呼び出す。
var input_area = document.getElementById('input-area') input_area.addEventListener("input", search);
function search()内で、XMLHttpRequestオブジェクトを作成します。
var ajax = new XMLHttpRequest();
XMLHttpRequest.open()メソッドでリクエストを作成します。引数asyncで、同期、非同期を決定することができます。デフォルトでは、非同期通信を行います。
今回は、リクエストメソッドGETを使用し、リクエスト先はsearch.php(後述)です。?q=+ wordで、入力されたwordをqという名前で渡しています。
var word = input_area.value; ajax.open('GET', 'search.php?q='+ word);
XMLHttpRequest.onreadystatechangeで、通信状態に変化があった時に実行するコールバック関数を登録することができます。XMLHttpRequest.readyStateによって、場合分けが可能です。
readyState value | state |
0 | UNSENT |
1 | OPENED |
2 | HEADERS_RECEIVED |
3 | LOADING |
4 | DONE |
今回は、通信が完了したとき(DONE)、XMLHttpRequest.responseTextで表示する名前のリストをJson形式で受け取り、それをフォームの<datalist></datalist>内に順番に追加しています。
PHPとJavaScriptでのJSONデータの受け渡しについては、“PHPでJsonデータを作成する方法”をご覧ください。
ajax.onreadystatechange = function(){ if(ajax.readyState == 4){ var suggest = document.getElementById("name-list"); var result_json_str = ajax.responseText; var name_list_tags = ""; if(result_json_str != ""){ var result_json_obj = JSON.parse(result_json_str); for(k in result_json_obj){ // get keys var item = result_json_obj[k]; name_list_tags += '<option value="' + item['name'] + '">'; } suggest.innerHTML = name_list_tags; } }
リクエストの送信は、XMLHttpRequest.send()で行います。
ajax.send();
3. phpでデータベースと通信
search.php では、検索語を受け取ってデータベースと通信を行います。
search.php
<?php $dsn = 'mysql:host=localhost;dbname=profile'; $username = 'root'; $password = '*******'; if ($_GET) { try { $query=$_GET["q"]; $dbh = new PDO($dsn, $username, $password); if($query==""){ echo ""; } else{ $sql ="select * from user where name like '".$query."%'"; $sth = $dbh->prepare($sql); $sth->execute(); $result = $sth->fetchAll(); $names = []; if($result){ foreach ($result as $row) { $names += array($row['id'] => array("name" => $row['name'], "age" => $row['age'], "icon" => $row['icon'])); } echo json_encode($names); } else{ echo ""; } } }catch (PDOException $e) { echo ""; exit(); } } ?>
以下は、上記ソースコードの詳細です。
データベースに接続する際には、PDOを使用します。(詳細: XAMPPでPHPを使ってMySQLにアクセスする)
$dsn = 'mysql:host=localhost;dbname=profile'; $username = 'root'; $password = '*******'; if ($_GET) { try { $query=$_GET["q"]; $dbh = new PDO($dsn, $username, $password);
SQLのSELECT文 WHERE LIKE句を使って、検索語に先頭が一致するデータを取得します。(関連: PHPで検索フォームを作成する)
$sql ="select * from user where name like '".$query."%'"; $sth = $dbh->prepare($sql); $sth->execute(); $result = $sth->fetchAll();
for文で取得したデータをたどり、Json形式のデータを生成します。echoで出力した内容を、JavaScriptのXMLHttpRequest.responseTextで受け取ることができます。(関連: PHPでJsonデータを作成する方法)
$names = []; if($result){ foreach ($result as $row) { $names += array($row['id'] => array("name" => $row['name'], "age" => $row['age'], "icon" => $row['icon'])); } echo json_encode($names); }
ソースコード全体
ソースコード全体は、https://gist.github.com/s-nako/dfd7bb90bcbd64f7a34b76ae339ab26bにあります。
結果
入力途中でサジェストが表示されるようになりました。

補足
このような検索では、一度取得したデータは、再利用することができます。(例えば、jだけの入力で[‘Jack Road’, ‘John Mark’, ‘John Perrill’]と出たら、ja, jb, jc…は、そこから探索すれば良いことになります)。
検索結果の上位を表示したり、毎回取得し直す必要があれば、今回のような方法になります。