RailsとjQueryでインクリメンタルサーチの処理を書いてみたのでまとめました。
これを利用したものをshot ideaというサービスで実装していたりします。
今回はposts/newページ内で利用するので:postsのcollection内に入れました。
#config/routes.rb resources :posts do collection do get 'search', :action => :search # posts/search end end
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" }, :status => 400 end
検索枠にテキストを入力し、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;