(2024.2.4 記)
下図のような、「何か入力すると、対応した情報が表示されるオートコンプリート機能(入力補完機能)を実装して欲しい」との要望に応えた内容を、忘備録として記した内容になります。
例えば、社員検索するとして、「田中」と入力すると「田中太郎」「田中次郎」「田中花子」といったように名前の羅列に「田中」が入っているデータを抽出し、オートコンプリートの要素として列記させるような感じです。
今回は汎用性を持たせるため、次のような仕様にしてみました。
①オートコンプリートの候補をDBから抽出する
②上記動作を入力の都度実行する
③選択したデータの内容と、その内容に割り振られているコードも併せて抽出する
④選択した内容は表示項目に、対応するコードは隠し項目にセットする
⑤同じ入力項目が複数存在しても、入力のあった項目でのみオートコンプリート機能が働くようにする
前提の話など含みますので、コードだけ知りたい人は見出しから飛んでください。
詳細は以下にて説明しています(初、中級者向け解説)。
※プロではないので、問題があったら教えて欲しい
(全行程の所要時間:コピペで終わり)
0.実行環境
■実行環境
・さくらVPN(メモリ:1GB、CPU:2コア、SSD:100GB)
・LinuxOS:Ubuntu18.04
・Apache:2.4
・MySQL:5.7
・PHP:7.2
1.実装方法
実装ソース:フロントサイド(PHP・HTML)
まずはフロントサイドの、PHP・HTMLの記述について。
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Language" content="ja" /> <!-- Ajaxを利用するにあたっての、CSSとJSを呼び出す(以下3つ) --> <link rel="stylesheet" rev="stylesheet" href="../css/jquery-ui.css" type="text/css" charset="utf-8" /> <script src="../js/jquery-3.6.0.min.js" charset="UTF-8"></script> <script src="../js/jquery-ui-1.13.0.js" charset="UTF-8"></script> <title>Document</title> </head> <body> ~中略~ <form action="test.php" method="post" name="update"> <table> <tr> <td>得意先</td> <td> <input id="cstm1" name="cstm1" type="text" size="32" onclick="return createAcCstm(this)" autocomplete="off" value="" />(自動検索) <input id="cstm1id" name="cstm1id" type="hidden" value="" /> </td> </tr> </table> </form> ~中略
<説明>
①Jqueryを利用するため、HTMLのヘッダに、CSS1つと、JS2つを呼び出す設定を記述します(7~9行目)。
②入力および表示用のテキストボックスを用意し、オートコンプリートの要素を取得するスクリプトの発火条件を書きます(21行目)。
イベントは「onclick()」を用い、発火スクリプトは「createAcCstm()」、スクリプトへ渡す引数は「this」としています。
「onclick()」イベントは、対象要素にマウスクリックでカーソルを入れただけでなく、TAB移動でカーソルが当たった時にも発火します。
発火スクリプトはとりあえず付けた名前なので、お好きにリネームして使ってください。
「this」は現在位置情報、ここでは、「要素種、要素ID、要素値」などの情報が複合的に詰込まれたオブジェクト値としてスクリプトの引数にして渡し、これをスクリプト先で受取る感じです。
③選択された内容のIDを格納する、隠し要素「input要素のhiddenタイプ」を用意します。
※ここでミソなのが、要素ID名を、textboxのID名に「id」を付けた「cstm1id」という名前にしている点です。(詳細は下記で説明)
実装ソース:フロントサイド(Javascript)
フロントサイドのスクリプトになります。
PHP・HTML上のファイルに直接書いてもいいですし、使いまわす用に別途jsファイルを用意・記述し、PHP・HTMLファイルから参照してもいいです。
//スクリプト <script type="text/javascript"> //○○マスタのオートコンプリート //対象のinput入力欄にカーソルが当たったら発火(引数として自身の「ID」を受ける) function createAcCstm(obj){ var name = "#" + obj.id; //検索結果表示用セレクター作成 var id = "#" + obj.id + "id"; //検索結果をhiddenタイプへ格納する時のセレクター作成 $(id).on("keyup", function () { //キーボードを押下して上がった際に発火 $(id).autocomplete({ //オートコンプリートの要素を、POSTしてDBから取得し配置 source: function(req, resp){ $.ajax({ url: "./autocomplete-empmst.php", type: "POST", cache: false, dataType: "json", data: { param1: req.term }, success: function(data){ resp(data); }, error: function(xhr, ts, err){ resp(['']); } }); }, //オートコンプリートの要素にフォーカスを当てた際のイベント focus: function(event, ui) { $(name).val(ui.item.label); $(id).val(ui.item.value); return false; }, //オートコンプリートの要素を選択した際のイベント select: function(event, ui) { $(name).val(ui.item.label); $(id).val(ui.item.value); return false; } }); }); } </script>
<説明>
①受け取った引数から要素IDを取得し、それをもとにスクリプト適用先のセレクタを作成する(6~7行目)。
②対象セレクタに、発火イベントを記述。発火条件は、「keyup」とし、その際にオートコンプリート機能を付与するという内容(9行目)。
③オートコンプリート機能の「source」プロパティに、オートコンプリートの候補としてAjaxを利用する設定を記述(13行目)。
Ajaxのパラメータとして・・・
「url」→POST先、GET先のパス
「type」→POSTかGET
「cache」→true or false だが、今回はfalseを指定
「dataType」→送信に使うデータのタイプで、今回はjson形式を指定。
「data」→POST通信時に渡すデータ、今回は「param1」という名前で、入力値「req.term」を指定。配列形式に複数指定できる。
これらを指定すると、データベースサイドで処理した内容が、オートコンプリートの要素として列記される。
④オートコンプリート機能の「focus」プロパティには、オートコンプリートの要素にフォーカスさせたときの処理を記述するが、今回は指定セレクタに値を格納する処理(チェックボックスに表示名を、隠し要素に表示名に対応するidを格納する処理)を記述している(31行目)。
⑤オートコンプリート機能の「select」プロパティには、オートコンプリートの要素を選択したときの処理を記述するが、今回は指定セレクタに値を格納する処理(チェックボックスに表示名を、隠し要素に表示名に対応するidを格納する処理)を記述している(37行目)。
※オートコンプリート機能のプロパティには他に、「delay」「minLength」といったものもあります。今回は初期値を利用したので記載はしなかったですが、次のような機能を持っていますので状況に合わせて利用するといいです。
・delay:入力があってから、オートコンプリートの要素が表示されるまでの時間(初期値:300ms)
・minLength:オートコンプリート機能が発火する際の最少文字数条件(初期値:1文字)
実装ソース:サーバサイド(PHP)
サーバサイド(POST通信先)の記述になります。
方法は何種類かありますが、オーソドックスに検索キーワードでDB検索し、値を配列に格納していく手法を取りました。
<?php //POST通信の受け取り $param1 = $_POST['param1']; //変数の初期化 $row = array(); //DB検索結果用 $res = array(); //返信用 //DB接続情報(各々の設定に変更して使ってください) $get_host = "test"; $get_dbname = "test"; $get_charset = "utf8"; $get_dbuser = "test"; $get_dbpass = "localhost"; try{ //DB接続 $connect_str = 'mysql:host='.$get_host.'; dbname='.$get_dbname.'; charset='.$get_charset; $pdo = new PDO($connect_str , $get_dbuser, $get_dbpass); //SQL文作成 //DBから名前を部分一致検索→条件に合致するIDと名前を抽出し、IDの昇順でソート $sql = "SELECT ID, NAME FROM CSTMMST WHERE 1=1 AND NAME LIKE :name AND DELETEFLG = 0 ORDER BY ID"; $prepare = $pdo->prepare($sql); $prepare->bindValue(':name', '%'.$param1.'%', PDO::PARAM_STR); $prepare->execute(); $flag = $prepare->execute(); $errinfo = $prepare->errorInfo(); $errcd = $errinfo[0].":".$errinfo[2]; $i = 0; while($row = $prepare->fetch()){ //返信用配列に連想配列として詰込み(「label」「value」をキーにしている) $res[$i] = array("label" => $row['NAME'], "value" => $row['ID']); $i++; } $pdo = null; } catch(PDOException $e){ $flag = false; $errcd = $e; $pdo = null; } //返信用配列を、JSON形式にエンコード echo json_encode($res); ?>
<説明>
①Ajax通信でPOSTされたPOSTの要素「param1」を受け取ります(3行目)。
②受け取った要素を検索キーワードとし、部分一致検索でDB検索します(23行目)。
③検索結果を連想配列にする(38行目)。
④連想配列をJSON形式にエンコードして、返信(52行目)。
先に返信用配列を初期化しているので、キーワードに対して何もヒットしなかった場合は空の値を返信し、表示側ではなにも表示されない動きになります。
余談(JqueryCSSの拡張)
JqueryのCSSについて、実は色々弄れます。
オートコンプリートの要素表示部分でカスタマイズした部分をちょこっと紹介します(”追記”の部分)。
<style> .ui-autocomplete { position: absolute; top: 0; left: 0; cursor: default; /*追記*/ max-height: 150px; //データ表示は縦150px分の枠 overflow-x: hidden; //横スクロールなし overflow-y: scroll; //150px分のデータを超えたらスクロールで表示 text-align: left; //左詰め表示 margin: 0; //オートコンプリートの要素の表示はセレクタの真下から開始 padding: 0em 0.5em 0em 0.5em; } </style>
2.最後に
独学でAjaxを触っていたので、理解するまで少々時間がかかりました。
この書き方がオーソドックスでアレンジしやすいかと思います。(と、後で自分で見返しても思い出しやすいのかなと。)
Ajaxについてはこのままコピペしても使えないので、各々の環境に合わせて要素名なり、SQL文なり、パラメータなりを変更しないといけない点が初学習者にとって難易度が高いのかなと思います。
コンソールに出力して見たり、alert()文で出力してみたりして、どのようなデータが行き来しているのか確認してみるのも手かと思います。
メインは自分自身の忘備録として記載していますが、ついでに少しでも誰かの参考になったら幸いです。
以上。
(不明点あればコメント頂ければ、可能な限りお答えします。)
▼オススメ教本▼
コメント