55

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

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

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

したがって、私が本当に求めているのは、Rails アプリでこれを機能させる方法の例であり、必ずしも JavaScript の構築方法の完全な説明ではありません (それは jquery-ui チームが私のために行ったことです =) )。

たとえば、オートコンプリート用のデータを準備する方法や、オートコンプリート機能をテキスト ボックスにアタッチする方法などです。

4

7 に答える 7

150

上記の質問に対する回答が得られなかったので、自分で解決する必要がありました。同じことを考えている人が他にもいる場合に備えて、思いついた解決策を投稿する必要があると思いました.

最初に知っておくべきことは、これが JavaScript の初めての経験であり、Rails のこつをつかんでいるところだということです。ですから、ぜひ、編集して、私がこれで間違っていると感じた場所にコメントしてください。正しいか間違っているか、少なくとも私はそれが私が望んでいたように機能することを知っています.

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


Rails アプリに JQUERY UI を組み込みます。

jQuery UIのコピーをダウンロードし、jquery -ui-1.8.2.custom.min.jsを/public/javascriptディレクトリ内に配置します。また、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' %>


オートコンプリートの JavaScript の例

次に、次のコードのチャンクを取得して、' new ' ビューの 1 つに配置します。これは任意のビューで使用できますが、文字通り「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 に伝えることです。以下を 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 内のすべての人がオートコンプリート テキスト フィールドに送信されました。これはまさに次のポイントをもたらします。


入力に基づいて、オートコンプリートの提案に使用されるフィルター データ

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

テキストフィールドに割り当てられたオートコンプリート ウィジェットは、テキストフィールドに入力したものをパラメーターとして source: に送信します。送信されるパラメーターは「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 

ここで、「Big Chunk of Code」内のコメントを確認してください。これは、これがどのように結びついているかを説明しているはずです。

最後に、オートコンプリートとして機能するテキストフィールドと、パラメーターの 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 の例では、パラメーターとして選択された別の値を送信する方法は、隠しフィールドを使用することであることが明確に示されています。

それが誰かに役立つことを願っています。

デール

于 2010-07-11T10:07:20.400 に答える
11

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

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

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

于 2014-01-04T04:59:45.750 に答える
7

Dale's Answerはかなりのチュートリアルです。最初のクエリを使用すると、データソースは入力した文字列で始まる一致のみを返すことに注意してください。単語内の任意の場所を検索する場合は、次のように変更する必要があります。

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

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

%(クエリに余分に追加されました)

于 2011-09-14T18:20:13.163 に答える
4

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

コンテキスト: ユーザーが入力した DJ の名前をオートコンプリートしようとしています - これも初心者です

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>
于 2015-04-23T19:19:11.243 に答える
2

これは大きな助けです。

それに加えて、ユーザーの画像の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 
于 2011-06-21T07:17:02.657 に答える
1

「ソース」が比較的小さい場合 (たとえば 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();
      }
    }
  });
});
于 2015-10-16T18:54:28.677 に答える