web-dev-qa-db-ja.com

Railsでjquery-uiオートコンプリートを設定する方法

私のRailsアプリで jquery-uiオートコンプリート を実装する方法についての助けが必要です。

ユーザーが顧客名を入力できるテキストフィールドにオートコンプリートを追加したい。数百人の顧客が存在する可能性があるため、推奨されるオートコンプリート値を「リモートで」、たとえば表から取得する必要があります(少なくともこれは私が理解していることです)。

私が理解できない主な点は、提案された値をオートコンプリートテキストボックスに提供する方法です。私はjquery-uiのドキュメントを読みましたが、この問題については少し気が重いようです。

だから私が本当に望んでいるのは、これをRailsアプリで動作させる方法の例であり、必ずしもjavascriptの構築方法の完全な説明ではありません(それはjquery-uiチームのものです私のためにやった=))。

たとえば、オートコンプリート用のデータをどのように準備し、テキストボックスにオートコンプリート機能をどのように添付しますか。

53
Oscar

さて、私は上記の質問に対する答えを得られなかったので、自分でそれを理解しなければなりませんでした。同じことを考えている人が他にいる場合に備えて、思いついた解決策を投稿すべきだと思いました。

あなたが知っておくべき最初のことは、これがjavascriptの私の最初の経験であり、Railsのこつを得ていることです。だから、ぜひ、私がこれでおかしくなったと思うところならどこでも自由に編集、コメントしてください。少なくとも、私はそれが私が望んでいたように機能することを知っています。

これを示す最良の方法は、例によると思います。以下は、アプリでオートコンプリートウィジェットを機能させる方法です。何が起こっているのか理解していない場合でも、先に進んでアプリに次のコードを追加することができます。その後、各部分がどのように機能するかを例で説明します。この後、使用に合わせて変更する方法または屈折する方法を把握する必要があります。


JQUERY UIを使用するRails APP。

jQuery UI のコピーをダウンロードして、/ public/javascriptディレクトリ内にjquery-ui-1.8.2.custom.min.jsを配置します。また、jQuery自体のコピーがあり、これも同じフォルダーにあることを確認してください。

JQuery UIファイルとjQueryファイルを、このようなapplication.html.erbファイルに含めます。
(一致する限り、ファイルに好きな名前を付けることができます)

<%= javascript_include_tag 'jquery.min', 'jquery-ui-1.8.2.custom.min.js' %>

ダウンロードしたjQuery UIには、すべてのCSSデータを含むフォルダーがあります。名前は、選択したテーマによって異なります。たとえば、「cupertino」というテーマを選択しました。 CSSデータを含むフォルダー全体を「/ public/stylesheets /」に配置します。次に、このようにCSSファイルをapplication.html.erbに含めます。

<%= stylesheet_link_tag 'cupertino/jquery-ui-1.8.2.custom' %>


オートコンプリートジャバスクリプトの例

次に、次のコードチャンクを使用して、「new」ビューのいずれかに配置します。これは任意のビューで使用できますが、「links_controller」というコントローラーに属する既存のビューから文字列を取得し、「people_controller」からデータをプルしていることを認識しています。 Railsについて十分に知っていれば、変更する必要があるものを見つけることができます。

-大量のコードを開始する-

    <script type="text/javascript">
    $(function() {

 // Below is the name of the textfield that will be autocomplete    
    $('#select_Origin').autocomplete({
 // This shows the min length of charcters that must be typed before the autocomplete looks for a match.
            minLength: 2,
 // This is the source of the auocomplete suggestions. In this case a list of names from the people controller, in JSON format.
            source: '<%= people_path(:json) %>',
  // This updates the textfield when you move the updown the suggestions list, with your keyboard. In our case it will reflect the same value that you see in the suggestions which is the person.given_name.
            focus: function(event, ui) {
                $('#select_Origin').val(ui.item.person.given_name);
                return false;
            },
 // Once a value in the drop down list is selected, do the following:
            select: function(event, ui) {
 // place the person.given_name value into the textfield called 'select_Origin'...
                $('#select_Origin').val(ui.item.person.given_name);
 // and place the person.id into the hidden textfield called 'link_Origin_id'. 
        $('#link_Origin_id').val(ui.item.person.id);
                return false;
            }
        })
 // The below code is straight from the jQuery example. It formats what data is displayed in the dropdown box, and can be customized.
        .data( "autocomplete" )._renderItem = function( ul, item ) {
            return $( "<li></li>" )
                .data( "item.autocomplete", item )
 // For now which just want to show the person.given_name in the list.
                .append( "<a>" + item.person.given_name + "</a>" )
                .appendTo( ul );
        };
    });
    </script>



<h1>New link</h1>

<% form_for(@link) do |f| %>
  <%= f.error_messages %>

<!-- Place the following text fields in your form, the names are not important. What is important is that they match the names in your javascript above -->
  <p>
        Select which person you want to link:<br /> 
<!-- This is the textfield that will autocomplete. What is displayed here is for the user to see but the data will not go anywhere -->
        <input id="select_Origin"/>
<!-- This is the hidden textfield that will be given the Persons ID based on who is selected. This value will be sent as a parameter -->
      <input id="link_Origin_id" name="link[Origin_id]" type="hidden"/>
  </p>
<!-- end of notes -->
  <p>
    <%= f.label :rcvd_id %><br />
    <%= f.text_field :rcvd_id %>
  </p>
  <p>
    <%= f.label :link_type %><br />
    <%= f.text_field :link_type %>
  </p>
  <p>
    <%= f.label :summary %><br />
    <%= f.text_area :summary %>
  </p>
  <p>
    <%= f.label :active %><br />
    <%= f.check_box :active %>
  </p>
  <p>
    <%= f.submit 'Create' %>
  </p>
<% end %>

-ビッグチャンクコードの終了-

さて、ドットを接続します。


提案として使用するオートコンプリートのデータを提供

オートコンプリートテキストフィールドがドロップダウン候補に表示できるデータを接続することから始めましょう。使用する形式はJSONですが、それをよく知らなくても心配しないでください...あなたの/他のアプリケーションの他の部分がそれを使用できるようにテキストをフォーマットする方法であることを知ることは十分に良いです。

テキストフィールドがオートコンプリートに必要とするデータは、「source:」オプションで指定されます。人々の名前とIDのリストをオートコンプリートに送信するため、以下をソースとして配置します。

source: '<%= people_path(:json) %>'  

上記のRailsヘルパーは文字列 "/ people.json"に変換されます。 "/ people.jsonにページを作成する必要はありません。 ".. json形式の/ peopleのリクエストを受信したときにpeople_controllerに何をするかを指示する必要があります。

def index  
# I will explain this part in a moment.
  if params[:term]
    @people = Person.find(:all,:conditions => ['given_name LIKE ?', "#{params[:term]}%"])
  else
    @people = Person.all
  end

  respond_to do |format|  
    format.html # index.html.erb  
# Here is where you can specify how to handle the request for "/people.json"
    format.json { render :json => @people.to_json }
    end
end

これで、@ peopleのすべての人がオートコンプリートテキストフィールドに送信されました。これは、次のポイントをもたらします。


入力に基づいて自動補完提案に使用されるフィルタデータ

オートコンプリートテキストフィールドは、入力内容に基づいて結果をフィルタリングする方法をどのように知っていますか?

テキストフィールドに割り当てられたオートコンプリートウィジェットは、ソースへのパラメーターとしてテキストフィールドに入力したものを送信します。送信されるパラメーターは「term」です。したがって、テキストフィールドに「Joe」と入力すると、次のようになります。

/people.json?term=joe

そのため、コントローラーには次のものがあります。

# If the autocomplete is used, it will send a parameter 'term', so we catch that here
    if params[:term]
# Then we limit the number of records assigned to @people, by using the term value as a filter.
      @people = Person.find(:all,:conditions => ['given_name LIKE ?', "#{params[:term]}%"])
# In my example, I still need to access all records when I first render the page, so for normal use I assign all. This has nothing to do with the autocomplete, just showing you how I used it in my situation.
    else
      @people = Person.all
    end

オートコンプリートテキストフィールドに入力された内容に基づいて@peopleに割り当てられるレコードの数を制限したので、オートコンプリートの提案のためにJSON形式に変換できるようになりました。

respond_to do |format|  
      format.html # index.html.erb  
      format.json { render :json => @people.to_json }
    end 

ここで、「コードの大塊」内のコメントを確認してください。このコメントは、これがどのように結び付いているかを説明します。

最後に、ページにオートコンプリートとして機能するテキストフィールドと、パラメーターのIDをコントローラーに送信する非表示フィールドが必要です。


独自のオートコンプリートをカスタマイズ

上記を理解し、使用に合わせて変更したい場合、コントローラーから返されるJSON形式は次のようになっていることを知っておく必要があります。

[{"person":{"id":1,"given_name":"joe","middle_name":"smith","family_name":"jones","nationality":"australian"}}]

この場合、javascriptのJSON文字列から異なる値にアクセスする方法は次のとおりです。

ui.item.person.name_of_some_attribute_such_as_given_name

ものすごく単純。 RailsのActiveRecord属性にアクセスするのによく似ています。

最後のメモ。この関数はjqueryウィジェットに組み込まれるべきだと思ったため、隠し値を提供する別の方法を探すのに多くの時間を費やしました。ただし、そうではありません。公式のjQueryの例では、別の値を送信してからパラメーターとして選択する方法は、非表示フィールドを使用することであることが明確に示されています。

それが誰かの助けになることを願っています。

デール

145
Oscar

jQuery 1.9/1.10はキーのオートコンプリートを削除し、uiAutocompleteを追加しました

.data("uiAutocomplete") instead of .data("autocomplete")

上記に変更した後、それは私のために働いた。

11
Arun

デールの答え は非常にチュートリアルです。注意すべきことの1つは、最初のクエリを使用すると、データソースは入力した文字列との一致beginningのみを返すことです。 Wordの任意の場所で検索したい場合は、変更する必要があります。

@people = Person.find(:all,:conditions =>
    ['given_name LIKE ?', "#{params[:term]}%"])

@people = Person.find(:all,:conditions =>
    ['given_name LIKE ?', "%#{params[:term]}%"])

(追加の%クエリへ)

7
piffle

私は基本的に以下のデールのアドバイスに従いましたが、私のコントローラーとjsファイルはわずかに違いました-彼のバージョンは何らかの理由で私に問題を与えていました(おそらくjquery更新のbc)

コンテキスト:ユーザーが入力したDJの名前をオートコンプリートしようとしています-また、newb

DJコントローラー

 class DjsController < ApplicationController
    def index
     if params[:term]
       @djs = Dj.is_dj.where('lower(name) LIKE ?', "%#{params[:term].downcase}%")
       respond_to do |format|  
          format.html
          format.json { render :json => @djs.map(&:name) }
       end
     end    
   end
 end

html.erbファイル

  <script type="text/javascript">

$(function() {  
    $('#select_Origin').autocomplete({
        source: '<%= djs_path(:json) %>'
      })

    $('.submit-comment').click(function(){
      var dj_name = $('#select_Origin').val();
      $('#link_Origin_id').val(dj_name);
    })

})

</script>
4
strohy1210

これは大きな助けです。

それに加えて、ユーザーの画像のURLを取得する必要がある場合、to_jsonでは不可能な場合があります。そのために、モデルに次のコードを追加します。

def avatar_url
    avatar.url(:thumb)
end

そして、コントローラでto_jsonの代わりにas_jsonを使用します

respond_to do |format|
    format.json {render :json => @users.as_json(:only => [:id,:name,:username], :methods => [:avatar_url]) }
end 
2
Bongs

「ソース」が比較的小さく、たとえば50個の要素である場合、実装は異なる(そしてより単純な)ことに注意することが重要です。公式ドキュメントの4番目の段落に記載されています。

https://api.jqueryui.com/autocomplete/

ローカルデータを使用する場合、必要なことはデータを取得してオートコンプリートメソッドに渡すだけで、フィルタリングが行われます。用語が入力されるたびにサーバーに行き来する必要はありません。

function filterByTags(tags) {
  $("#stories-filter").autocomplete({
     source: tags,
     autoFocus: true
  });
}

$("#stories-filter").click(function() {
  $.ajax({
    dataType: 'json',
    method: 'GET',
    url: 'tags/index',
    data: $(this).data('project-id'),
    success: function (response) {
      if(response.success) {
        var tags = response.data.tags;
        filterByTags(tags);
      }
    },
    error: function (response) {
      if(response.status === 422) {
        var $errors = 'There are no tags in this project',
            $errorsContainer = $('.error-container');
        $errorsContainer.append($errors);
        $errorsContainer.show();
      }
    }
  });
});
1
vicocas