【Java】【Google App Engine】GAEでインクリメンタルサーチ【javascript】
2011-12-28 02:07:05 Wed
■GAEでインクリメンタルサーチ
インクリメンタルサーチ(候補検索)を行うには前方一致検索をする必要がある。
SQL的に記述すると param% のような記述になるがこれをGAEの制限されたDatastoreで表現すると次のようになる。
Slim3を使っています。
public Listsearch(Map params){
IncrementalSearchMasterMeta meta = IncrementalSearchMasterMeta.get();
String param = (String)params.get("send_data");
String param2 = param + "\uFFFD";
Listlist = Datastore.query(meta).filter(meta.text.greaterThanOrEqual(param)).filter(meta.text.lessThan(param2)).limit(10).asList();
return list;
}
こんな感じ。
フィルタクエリで param <= text AND text < param2 と指定しています。
param:あ <= text AND text < param2: あ + \uFFFDという感じの範囲検索で実現できます。
上記であれば「あ」から始まるものをすべて取得できます。
http://code.google.com/p/objectify-appengine/wiki/FrequentlyAskedQuestions
http://blog.virtual-tech.net/2009/10/google-app-engine-key.html
■ちょっと厄介なクライアントコーディング
インクリメンタルサーチをすればGoogleみたいに入力ボックスの下にびろっと出して選択できるようにしたくなりました。
で適当に作りました。
スクロールバーのこととか、下キー上キーのキー制御のロジックとか入っていませんがメモ。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset=utf-8 />
<title>Test</title>
<script src="/common/js/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
// tableタグを生成して非表示で追加
var table = $('<table id="incremental" onclick="onClick(event, true)" onmouseout="onMouseOut(event,true)" onmouseover="highlight(event,true)" style="position: absolute;overflow: visible;top: 73px;left: 8px;width: 155px;border: 1px #E3E3E3 solid;border-collapse: collapse;border-spacing: 0;text-alighn: left;display: none;cursor: pointer; background-color: white;"><tr><td>aaa</td></tr></table>');
$('html').append(table);
// 入力ボックスへのイベント設定
$("[name=keyword]").bind("keyup", onCange);
$("[name=keyword]").bind("blur", onBlur);
// 登録ボタンへのイベント設定
$("#regBtn").bind("click", register);
});
// インクリメンタルサーチの候補一覧が選択されたとき選択されている行のテキストを入力テキストに代入して候補一覧を非表示にする
function onClick(e,b){
var src;
// Netscape イベント処理用の分岐
if (navigator.appName == "Netscape"){
src = e.target;
}else{
src = e.srcElement;
}
if (src.tagName == "TD") {
if(b==true) { // mouseOver, and highlight {
var text = src.textContent;
$("[name=keyword]").val(text);
}else{ // mouseOut, restore original color
}
}
$("#incremental").hide();
}
// マウスが候補一覧上にあるとき特定行の背景色を変更する
function highlight(e,b) {
var src;
// Netscape イベント処理用の分岐
if (navigator.appName == "Netscape"){
src = e.target;
}else{
src = e.srcElement;
}
if (src.tagName == "TD") {
if(b==true) { // mouseOver, and highlight {
src.originColor=src.style.backgroundColor;
src.style.backgroundColor="gray";
}else{ // mouseOut, restore original color
src.style.backgroundColor=src.originColor;
}
}
}
// マウスが候補検索一覧上にあって背景色が変更された特定行からマウスを違うところへ移動したとき背景色を元に戻す
function onMouseOut(e,b){
var src;
// Netscape イベント処理用の分岐
if (navigator.appName == "Netscape"){
src = e.target;
}else{
src = e.srcElement;
}
if (src.tagName == "TD") {
if(b==true) { // mouseOver, and highlight {
src.originColor=src.style.backgroundColor;
src.style.backgroundColor="white";
}else{ // mouseOut, restore original color
src.style.backgroundColor=src.originColor;
}
}
}
// 入力テキストに文字が入力されたときajaxで候補一覧を取得しこれを候補一覧に表示する
function onCange(){
var value = $("[name=keyword]").val();
if(value == ""){
return;
}
jQuery.ajax({
url: "incremental/search",
cache: true,
data: {"send_data": value},
success: function(msg){
// テーブル内のHTMLを空にする
$("#incremental").empty();
// 取得したデータをテーブル内に反映する
var list = msg["retlist"];
for(var i = 0; i < list.length; i++){
var tr = $("<tr><td>" + list[i]["text"] + "</td></tr>");
$("#incremental").append(tr);
}
$("#incremental").show();
}
});
}
// 入力テキストからフォーカスが外れたとき200ミリ秒して候補一覧を非表示にする
function onBlur(){
setTimeout(function(){$("#incremental").hide();},200);
}
// 登録ボタンが押下されたとき入力テキストの入力内容をパラメータとしてajax通信し候補キーワードとして登録する
function register(){
var value = $("[name=keyword]").val();
if(value == ""){
$('#logarea').prepend('<p>キーワードを入力して下さい。' + new Date() + '</p>');
return;
}
jQuery.ajax({
url: "register",
cache: true,
data: {"send_data": value},
success: function(msg){
$('#logarea').prepend('<p>登録完了。' + new Date() + '</p>');
}
});
}
</script>
</head>
<body>
<p>search test</p>
<input type="text" name="keyword" style="width: 150px; height: 17px;">
<input type="button" value="register" id="regBtn" >
<div id="logarea"></div>
</body>