Как настроить автозаполнение jquery-ui в Rails - PullRequest
53 голосов
/ 06 июля 2010

Мне нужна помощь по реализации автозаполнения jquery-ui в моем приложении Rails.

Я хочу добавить автозаполнение в текстовое поле, где пользователь может ввести имя клиента. Поскольку могут быть сотни клиентов, мне нужно будет извлекать предложенные значения автозаполнения «удаленно», например, из таблицы (по крайней мере, это то, что я понимаю).

Основной момент, который я не понимаю, - как указать предлагаемые значения в текстовом поле автозаполнения. Я прочитал документы по jquery-ui, но мне кажется, что я немного разбираюсь в этом вопросе.

Итак, что мне действительно нужно, это пример того, как я могу заставить это работать в приложении Rails, не обязательно полное описание того, как построен javascript (именно это и сделала команда jquery-ui для меня =) ).

Например, как подготовить данные для автозаполнения и как прикрепить функцию автозаполнения к текстовому полю.

Ответы [ 6 ]

145 голосов
/ 11 июля 2010

Ну, я так и не получил ответ на свой вопрос выше, поэтому мне пришлось самому в этом разобраться.Я подумал, что должен опубликовать решение, которое придумал, на случай, если найдутся другие ребята, которым интересно то же самое.

Первое, что вы должны знать, это то, что это мой первый опыт работы с javascript, и яЯ только знакомлюсь с Rails.Так что, во что бы то ни стало, не стесняйтесь редактировать, комментировать везде, где вы чувствуете, что я ошибся с этим.Правильно или нет, по крайней мере, я знаю, что это работает так, как я хотел.

Я думаю, что лучший способ показать это на примере.Итак, вот как я получил виджет автозаполнения для работы в моем приложении.Вы можете пойти дальше и добавить следующий код в свое приложение, даже если вы не понимаете, что происходит, тогда мы можем рассмотреть, как каждая часть работает на примере.После этого вы должны понять, как изменить его для использования или рефракторинга.

ВКЛЮЧАЙТЕ JQUERY UI В ПРИЛОЖЕНИЕ RAILS.

Загрузите копию jQuery UI и поместите jquery-ui-1.8.2.custom.min.js в вашем каталоге / public / javascript .Также убедитесь, что у вас есть копия самого jQuery, и она также находится в той же папке.

Включите файл пользовательского интерфейса jQuery и файл jQuery в файл application.html.erb , например:этот.(вы можете называть файлы по своему усмотрению, если они совпадают)

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

При загрузке пользовательского интерфейса jQuery у вас будет папка, содержащая все ваши данные CSS.Название будет меняться в зависимости от выбранной вами темы, например, я выбрал тему « cupertino ».Поместите всю папку, содержащую ваши данные CSS, в « / public / stylesheets / ».Затем включите файл CSS в файл application.html.erb следующим образом.

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

ПРИМЕР АВТОКОМПЛЕКТА JAVASCRIPT

Теперь возьмите следующий фрагмент кода и поместите его в один из ваших новых представлений.Вы можете использовать это в любом представлении, но поймите, что я буквально взял его из существующего представления, принадлежащего контроллеру, называемому "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, но не беспокойтесь, если вы с ним не знакомы ... я тоже =).Достаточно хорошо знать, что это способ форматирования текста, чтобы его могли использовать другие части вашего / других приложений.

Данные, которые понадобятся текстовому полю для автозаполнения, указаны в 'источник: 'опция.Поскольку мы хотим отправить список имен людей и их ID в автозаполнение, мы будем указывать в качестве источника следующее:

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

Помощник rails выше переведет в строку " / people.* 1058 JSON *».Вам не нужно создавать страницу в " / people.json ".Что вам нужно сделать, это сказать вашему people_controller, что делать, когда он получает запрос для / people в формате .json.Добавьте в ваш 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 ». Поэтому, если вы введете «Джо» в текстовое поле, мы сделаем следующее:

/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 

Теперь просто просмотрите комментарии внутри «Большого куска кода», которые должны объяснить остальную часть того, как это связано друг с другом.

В конце у вас должно появиться текстовое поле на странице, которое действует как автозаполнение, и скрытое поле, которое отправит идентификатор параметра в ваш контроллер.


НАСТРОЙТЕ СВОЙ АВТОМОБИЛЬ

Как только вы поймете вышеизложенное и захотите изменить его для своего использования, вы должны знать, что формат, возвращенный JSON из вашего контроллера, выглядит следующим образом:

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

В этом случае доступ к различным значениям из строки JSON в вашем javascript будет следующим:

ui.item.person.name_of_some_attribute_such_as_given_name

Довольно просто. Очень похоже на доступ к атрибуту ActiveRecord в Rails.

Последнее замечание. Я потратил много времени в поисках другого способа предоставления скрытого значения, так как думал, что эта функция должна была быть встроена в виджет jquery. Однако, это не так. В официальном примере jQuery четко показано, что способ отправки значения, отличного от выбранного в качестве параметра, заключается в использовании скрытого поля.

Ну, я надеюсь, это кому-нибудь поможет.

Дейл

10 голосов
/ 04 января 2014

jQuery 1.9 / 1.10 удалил автозаполнение ключа и добавил uiAutocomplete

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

После изменения выше он работал для меня.

7 голосов
/ 14 сентября 2011

Ответ Дейла - довольно урок. Следует отметить, что при использовании вашего первого запроса источник данных будет возвращать только совпадения начиная с с введенной вами строкой. Если вы хотите искать в любом месте слова, вам нужно изменить:

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

до

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

(добавлен дополнительный % к запросу)

4 голосов
/ 23 апреля 2015

Я в основном следовал совету Дейла, приведенному ниже, но мои файлы контроллера и js немного отличались - его версия по какой-то причине вызывала у меня проблемы (возможно, bc обновлений jquery)

Контекст: я пытаюсь автозаполнять именанабранных пользователями диджеев - также новый

контроллер диджеев

 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 file

  <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>
2 голосов
/ 21 июня 2011

Это отличная помощь.

В дополнение к этому, в случае, если вам нужно получить 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 
1 голос
/ 16 октября 2015

Важно отметить, что если ваш «источник» относительно мал, например, 50 элементов, реализация должна быть другой (и намного проще).Это упоминается в четвертом абзаце официального документа:

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();
      }
    }
  });
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...