RailsとjQueryでインクリメンタルサーチの処理を書いてみたのでまとめました。
これを利用したものをshot ideaというサービスで実装していたりします。
今回はposts/newページ内で利用するので:postsのcollection内に入れました。
1 2 3 4 5 6 7 | #config/routes.rb resources :posts do collection do get 'search' , :action => :search # posts/search end end |
params[:q]に、クエリのデータが入っています。
Model:Postのtitleから、クエリの文字列を含むものを最大3件取得しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #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イベントも加えないと、思い通り動かないかも?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | // 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; |