Ruby(Rails3)とjQueryでインクリメンタルサーチの処理を書いてみたのでまとめました。
##元記事
下記エントリの転載になります。
RailsとjQueryで、簡単インクリメンタルサーチ - rokuroFire
##本エントリの前提
- インクリサーチは、ポスト(Model:Post)のタイトル(title)を検索
- json形式でデータを受け取り、JSでページを更新
##ルーティング
今回はposts/newページ内で利用するので:postsのcollection内に入れました。
config/routes.rb
resources :posts do
collection do
get 'search', :action => :search
# posts/search
end
end
##Controller
params[:q]に、クエリのデータが入っています。
Model:Postのtitleから、クエリの文字列を含むものを最大3件取得しています。
app/controllers/posts_controller.rb
def search
raise unless params[:q]
lists = []
results = Post.where("title like ?", "%#{params[:q]}%").order('count DESC').limit(3)
results.each do |result|
lists.push({:title => result.title) if result.title
end
render :json => { :lists => lists, :result => "success"}
return true
rescue
render :json => {:result => "error_search" }
end
##JavaScript
検索枠にテキストを入力し、500ms経ったあとに1回ajax通信を行います。
onkeypressでイベントを発生させているため、文字入力を行う度にincSearch関数が実行されます。関数内でclearTimeoutを実行することで、関数実行時にタイマーがリセットされるため、関数の実行回数 = 通信の回数にはならないようにしています。
※ DOMの処理は省略
※ 実際は、エンターキーを押した時の分岐やonblurイベントも加えないと、思い通り動かないかも?
application.js
// ajax処理
function incSearch(){
// タイマーをストップ
clearTimeout(incSearch.timeid);
// setTimeout 500ms
incSearch.timeid = setTimeout(function(){
// inputに入力されているテキストを取得
var query = tgtInput.value;
if(query.length == 0) return false;
// ajax処理
jQuery.ajax({
type : 'GET',
url : '/posts/search',
data : {
q : query
},
timeout : 1500,
success:function(data){
if(data.result != "success") return false;
changeDom(data.lists);
},
error:function(){
// エラー時の処理をここに書く
return false;
}
});
},500);
};
incSearch.timeid = "";
// DOMの変更
// 引数listsに検索結果が入っている
function changeDom(lists){
if(lists.length == 0) return false;
// ここにDOMを書き換える処理を書く
};
// ターゲットとなるinputタグにイベント追加
var tgtInput = document.getElementById('tgtInput');
tgtInput.onkeydown = incSearch;