ruby-on-rails 如何在Rails中设置jquery-ui自动完成

xdyibdwo  于 2022-12-27  发布在  Ruby
关注(0)|答案(7)|浏览(104)

我需要一些关于如何在我的Rails应用程序中实现jquery-ui autocomplete的帮助。
我想在用户可以输入客户名称的文本字段中添加自动完成功能。由于可能有数百个客户,我需要“远程”从表中提取建议的自动完成值(至少我是这么理解的)。
我不理解的主要问题是如何向自动完成文本框提供建议值,我读过jquery-ui文档,但我似乎对这件事有点太过关注。
因此,我真正想要的是一个如何在Rails应用程序中使用它的示例,而不一定是对javascript如何构建的完整描述(这是jquery-ui团队为我所做的=)。
例如,如何为自动完成准备数据,以及如何将自动完成功能附加到文本框。

62lalag4

62lalag41#

我一直没有得到上面问题的答案,所以我不得不自己解决。我想我应该把我想到的解决方案贴出来,以防有其他人也想知道同样的事情。
首先你应该知道的是这是我第一次使用javascript,我刚刚掌握了Rails的窍门。所以无论如何,你可以随意编辑,评论任何你觉得我做错的地方。对或错,至少我知道它是按照我想要的方式运行的。
我认为最好的方法是通过例子来说明这一点。下面是我如何让自动完成小部件在我的应用程序中工作的。即使你不明白发生了什么,你也可以继续把下面的代码放在你的应用程序中,然后我们可以通过例子来了解每个部分是如何工作的。在这之后,你应该掌握如何修改它以供你使用或折射它。

将JQUERY UI包含在您的Rails应用程序中。

下载[jQuery UI][ui]的副本,并将jquery-ui-1.8.2.custom.min.js放入**/public/javascript目录中,还要确保您有jQuery本身的副本,并且该副本也在同一个文件夹中。
application.html.erb**文件中包含jQuery UI文件和jQuery文件,如下所示。
(you只要文件匹配,您可以随意命名文件)

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

在jQuery UI的下载中,您将拥有一个包含所有CSS数据的文件夹。名称将根据您选择的主题而变化,例如我选择了主题“库比蒂诺”。将包含CSS数据的整个文件夹放入“/public/stylesheets/”。然后将CSS文件包含在您的application.html.erb中,如下所示。

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

自动完成Java脚本示例

现在把下面的代码块放到你的一个“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 helper会转换成一个字符串“/people.json"。你不需要在“/people.json"创建一个页面。你需要做的是告诉你的people_controller当它接收到一个.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中的所有人都被发送到autocomplete文本域,这就引出了下一点。

用于自动完成建议的过滤器数据,基于输入

自动完成文本域如何知道如何根据您键入的内容过滤结果?
分配给文本域的autocomplete小部件会将您在文本域中键入的任何内容作为参数发送到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

现在,回顾一下“大块代码”中的注解,它应该解释了其余的代码是如何联系在一起的。
最后,您的页面上应该有一个文本字段作为自动完成,还有一个隐藏字段将参数中的ID发送到控制器。

自定义您自己的自动完成功能

一旦理解了上面的内容并想修改它以供使用,就应该知道从控制器返回的JSON格式如下所示:

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

在这种情况下,从JavaScript中的JSON字符串访问不同值的方法是:
ui.item.person.name属性的www.example.com,例如给定名称
漂亮,简单,很像在Rails中访问ActiveRecord属性。
最后一点注意。我花了很多时间寻找一种不同的方法来提供隐藏值,因为我认为这个函数应该内置到jquery小部件中。然而,事实并非如此。在官方jQuery示例中清楚地显示,发送一个不同的值然后选择为参数的方法是使用一个隐藏字段。
日期[用户界面]:http://jqueryui.com/download

yrwegjxp

yrwegjxp2#

jQuery 1.9/1.10删除了自动完成键并添加了uiAutocomplete

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

经过修改,以上述,它为我工作.

3b6akqbq

3b6akqbq3#

Dale's Answer是一个很好的教程。需要注意的一点是,使用你的第一个查询,数据源只会返回与你输入的字符串开头的匹配项。如果你想搜索单词中的任何地方,你需要修改:

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

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

(向查询添加了额外的%

2ul0zpep

2ul0zpep4#

我基本上遵循了下面Dale的建议,但是我的控制器和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>
jv2fixgn

jv2fixgn5#

这是一个很大的帮助。
除了它的情况下,如果你需要获取用户的图像的url,它可能不可能与to_json。为此,添加以下代码在模型。

def avatar_url
    avatar.url(:thumb)
end

然后在控制器中使用as_json代替to_json

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

wpcxdonn6#

需要注意的是,如果你的“源代码”相对较小,比如只有50个元素,那么实现方式就应该有所不同(而且要简单得多)。官方文档的第四段提到了这一点:
https://api.jqueryui.com/autocomplete/
当使用本地数据时,你所需要做的就是获取数据并将其传递给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();
      }
    }
  });
});
vkc1a9a2

vkc1a9a27#

既然这是旧的,但谷歌仍然来到这里,一个关于主要答案的小说明,这本质上是好的,但有些事情发生了变化:

  • 参见关于jquery已将.data(“uiAutocomplete”)更改为.data(“autocomplete”)的回答
  • 另外,我建议在资源集合上使用一个单独的路径来处理json
  • 使用rabl来创建较小的json(或者为较大的模型使用pluck)
  • like,not like,表示不区分大小写
  • %在前面,所以搜索不仅仅是start_with。
  • 方法中的有效遍历,如item.person.name仅为item.name(因此删除.person)
  • 使用咖啡(以哈马尔计)
  • 使用限值,其中:人员。其中('给定名称类似?',“%#{参数[:术语]}%”)。限制(20)

相关问题