52

Necesito ayuda sobre cómo implementar un jquery-ui autocomplete en mi aplicación Rails.Cómo configurar el autocompletado de jquery-ui en Rails

Quiero agregar autocompletado a un campo de texto donde el usuario puede ingresar el nombre de un cliente. Como puede haber cientos de clientes, tendré que extraer los valores de autocompletado sugeridos 'de forma remota', como en una tabla (al menos esto es lo que entiendo).

El punto principal que no estoy entendiendo es cómo proporcionar los valores sugeridos al cuadro de texto de autocompletado. He leído los documentos de jquery-ui, pero parece ser un poco denso en este asunto.

Así que lo que realmente busco es un ejemplo de cómo puedo hacer que esto funcione en una aplicación Rails, no necesariamente una descripción completa de cómo se construye el javascript (eso es lo que el equipo jquery-ui ha hecho por mí =)).

Por ejemplo, ¿cómo preparo los datos para la autocompletación y cómo adjunto la funcionalidad de autocompletado a un cuadro de texto?

Respuesta

145

Bueno, nunca obtuve una respuesta a mi pregunta anterior, así que terminé teniendo que resolverlo por mí mismo. Pensé que debería publicar la solución que surgió en caso de que haya otros tipos que se estén preguntando lo mismo.

Lo primero que debes saber es que esta es mi primera experiencia con JavaScript, y que estoy acabando con el truco de Rails. Así que, por favor, siéntase libre de editar, comente en cualquier lugar que sienta que me he equivocado con esto. Correcto o incorrecto, al menos sé que funciona de la manera que yo quería.

Creo que la mejor manera de mostrar esto es por ejemplo. Así que lo siguiente es cómo obtuve el widget de autocompletar para que funcione en mi aplicación. Puede seguir adelante y poner el siguiente código en su aplicación, incluso si no comprende lo que está sucediendo, luego podemos repasar cómo funciona cada parte con el ejemplo. Después de esto, debe tener una idea de cómo modificarlo para su uso o refractarlo.


INCLUYEN jQuery UI CARRILES EN SU APP.

descargar una copia de la jQuery UI y colocar jquery-ui-1.8.2.custom.min.js dentro de su directorio/pública/javascript. También asegúrese de tener una copia de jQuery y que también esté en la misma carpeta.

Incluya el archivo jQuery UI y el archivo jQuery en su archivo application.html.erb de esta manera.
(se puede nombrar los archivos como desee, siempre y cuando coinciden)

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

En la descarga de jQuery UI, tendrá una carpeta que contiene todos los datos de CSS. El nombre variará en función del tema que elija, por ejemplo, elegí el tema 'cupertino'. Coloque la carpeta completa que contiene sus datos de CSS en '/public/stylesheets/'. Luego incluya el archivo CSS en su application.html.erb de esta manera.

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


Ejemplo de autocompletar JavaScript

Ahora toma el siguiente fragmento de código y colocarlo en uno de sus puntos de vista 'nuevos'. Puedes usar esto en cualquier vista, pero te das cuenta de que literalmente la he tomado de una vista existente que pertenece a un controlador llamado 'links_controller', y está extrayendo datos de un 'people_controller'. Espero que sepa lo suficiente sobre Rails para resolver lo que necesita cambiar para que esto funcione para usted.

- Comience gran trozo de código -

<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 %> 

- Finalizar gran trozo de código -

Bueno ahora a conectar los puntos.


proporcionar datos para Autocompletar para su uso como SUGERENCIAS

Vamos a empezar conectando hasta algunos datos que el campo de texto de autocompletar puede mostrar en el menú desplegable sugerencias. El formato que utilizaremos es JSON, pero no se preocupe si no está familiarizado con él ... tampoco lo estoy =). Es suficiente saber que es una forma de formatear texto para que otras partes de usted/otras aplicaciones puedan usarlo.

Los datos que el campo de texto necesitará para la autocompleta se especifican en la opción 'source:'. Como queremos enviar una lista de los nombres de personas y su ID a la autocompletar, colocaremos lo siguiente como fuente.

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

los rieles ayudante anterior se traducirá en una cadena "/people.json". No necesita crear una página en "/people.json". Lo que debe hacer es decirle a su controlador de personas qué hacer cuando recibe una solicitud para/personas con el formato .json. Ponga lo siguiente en su 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 

Ahora tenemos todas las personas en @people de ser enviado al campo de texto de autocompletar. Esto trae al siguiente punto.


datos de filtro UTILIZADOS PARA Autocompletar sugerencia, basada en la entrada

¿De qué manera el campo de texto de autocompletar saben cómo filtrar los resultados en función de lo que escribe?

El widget de autocompletar asignado al campo de texto va a enviar lo que se teclea en el campo de texto como parámetro a la fuente :. El parámetro que se envía es "término".Así que si tuviera que escribir "Joe" en el campo de texto, estaríamos haciendo lo siguiente:

/people.json?term=joe 

Es por eso que tenemos el siguiente en el controlador:

# 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 

Ahora que hemos limitado la cantidad de registros asignados a @personas en función de lo que se escribe en el campo de texto de autocompletar, ahora podemos convertirlo en formato JSON para las sugerencias de autocompletar.

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

Ahora, basta con revisar los comentarios dentro de la "gran parte del Código", que debe explicar el resto de cómo esto se relaciona entre sí.

Al final debe tener un campo de texto en su página que actúa como autocompletar y un campo oculto que enviará la ID en un parámetro a su controlador.


personalizar sus propios Autocompletar

Una vez que entienda lo anterior y desea modificarlo para su uso, debe saber que el formato JSON regresó de su controlador se ve así:

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

La manera de acceder a los diferentes valores de la cadena JSON en su javascript en este caso sería:

ui.i tem.person.name_of_some_attribute_such_as_given_name

Pretty, simple. Es muy parecido a acceder a un atributo ActiveRecord en Rails.

Una última nota. Pasé mucho tiempo buscando una forma diferente de proporcionar el valor oculto, ya que pensé que esta función debería haber sido incorporada en el widget jquery. Sin embargo, éste no es el caso. Se muestra claramente en el ejemplo jQuery oficial que la forma de enviar un valor diferente y luego se selecciona como un parámetro, es usar un campo oculto.

Bueno, espero que ayude a alguien.

Dale

+2

Gracias. Esta fue una gran ayuda. – rangalo

+2

Buena explicación. Hay muchos consejos y trucos por partes del lugar, pero hasta ahora no había encontrado un ejemplo conciso y de extremo a extremo. Gracias por la ayuda ... – Nuby

+3

@paz deberías tener tu propio blog si no lo has hecho :) muy lindo, justo lo que estaba buscando. – jn29098

2

Esto es de gran ayuda.

Además de esto, en caso de que necesite recuperar la URL de la imagen del usuario, es posible que no sea posible con to_json. Para eso agrega el siguiente código en el modelo.

def avatar_url 
    avatar.url(:thumb) 
end 

Y luego, en vez de controlador to_json uso as_json

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

Dale's Answer es bastante el tutorial. Una cosa a tener en cuenta es que al usar su primera consulta, la fuente de datos solo devolverá las coincidencias comenzando con con la cadena que escriba.Si desea buscar en cualquier parte de la palabra, tiene que cambiar:

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

a

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

(añadido un extra % a la consulta)

10

jQuery 1.9/1.10 removido el autocompletar clave y añadido uiAutocomplete

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

Después de modificar a abov e, funcionó para mí.

+0

Esta debería ser la mejor respuesta. –

4

básicamente siguió el consejo de Dale abajo pero mi controlador y archivos js fueron ligeramente Diff- su versión me estaba dando problemas por alguna razón (tal vez bc de cambios jquery)

Contexto: Estoy tratando de autocompletar nombres de DJ tecleó los usuarios - también es un Novato

DJ controlador

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 

archivo 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> 
1

Es importante tener en cuenta que si su 'fuente' es relativamente pequeña, por ejemplo 50 elementos, la implementación debería ser diferente (y mucho más simple). Se menciona en el cuarto párrafo del documento oficial:

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

Al utilizar datos locales todo lo que necesita hacer es obtener los datos y pasarlo al método de autocompletar, y lo hará el filtrado para usted . No necesita ir y venir al servidor cada vez que se ingresa un término.

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(); 
     } 
    } 
    }); 
}); 
Cuestiones relacionadas