29 Jun
duccio

duccio il 29 June 2007 parla di Rails Snippet

Ajax Autocomplete per Rails con passaggio di “id”

Un limite dell’autocomplete è che il valore che viene passato in post è quello presente nella textbox utilizzata per l’autocomplete, questo significa che per recuperare l’id associato a quel valore dovete eseguire un accesso al database che in realtà è inutile!

Per evitare questo problema potreste creare un helper per l’autocomplete leggermente diverso, che sull’after_update dell’autocomplete esegua un js ch aggiorna una text_field da passare in post alla funzione prevista.

Ecco il text_field_id_with_auto_complete:

    1   def text_field_id_with_auto_complete(object, method)  
    2    update = "obj = getElementsByClassName(document,'selected');"
    3    update += "document.getElementById('friend_id').value = getElementsByClassName(obj[0],'id-value')[0].innerHTML;"
    4    text_field_with_auto_complete(object, method, {}, {:skip_style => true, :frequency => "0.5", :select=>"choosethis", :with => "fieldname=value", :after_update_element => "function(element, value){"+update+"}"})
    5   end

Nella vostra vista usate questo codice:

    1 <% form_remote_for :user, :url => {:controller => "account", :action => 'add_friend'}, :html => { :id => "add-friends-to-user" } do |form| -%>
    2 <%= text_field_id_with_auto_complete :friend, :login %>
    3 <%= hidden_field :friend, :id %>
    4 <%= submit_tag("Add a friend") %>
    5 <% end -%>

In questo modo dopo aver scelto il valore suggerito dall’autocomplete parte il js (quello della funzione nell’helper) che aggiorna l’hidden_field da passare in post. Qui vedete il codice da mettere nel vostro controllore, questa funzione prende il valore passato dalla textbox e restituisce una collezione di risultati che popoleranno il div dei suggerimenti:

    1 def auto_complete_for_friend_login
    2     @users = User.find(:all, 
    3     :conditions => [ 'LOWER(login) LIKE ? and id <> ?',
    4       params[:friend][:login].downcase + '%', session[:user]], 
    5       :order => 'login ASC',
    6       :limit => 8)
    7       render :partial => '/shared/user'
    8     end

Il parziale “_user”:

    1 <ul>
    2 <% for user in @users do %>
    3   <li id="user_<%= user.id %>">
    4   <p class="choosethis"><%= user.login %></p>
    5   <div class="id-value" style="display:none"><%= user.id %></div>
    6   </li>   
    7 <% end %>
    8 </ul>

Il js usa una funzione che è getElementByClassName da mettere nell’application.js:

    1 function getElementsByClassName(node, classname)
    2 {
    3     var a = [];
    4     var re = new RegExp('\\b' + classname + '\\b');
    5     var els = node.getElementsByTagName("*");
    6     for(var i=0,j=els.length; i<j; i++)
    7         if(re.test(els[i].className))a.push(els[i]);
    8     return a;
    9 }

Addesso in post avrete l’id dell’oggetto selezionato nei suggerimenti dell’autocomplete, in questo modo evitate una inutile query testuale per recuperare l’id.

3 Commenti a “Ajax Autocomplete per Rails con passaggio di “id””

  1. stefano il 8 February 2008 alle 19:29 dice:

    Salve,
    Ho provato la tua soluzione. Mi funziona in parte; ovvero mi viene correttamente caricato la variabile definita ‘hidden’ ma non vi viene piu’ aggiornato il campo testuale relativo.
    In piu’ ho la necessita’ di utilizzare piu’ di un campo che faccia uso dell’auto-complete . In questo modo selezioando piu’ di un valore nei rispettivi campi, mi vendono caricati i campo ‘hiden’ tutti con lo stesso valore.
    Puoi per favore darmi qualche indicazione in merito?

    Cordiali saluti
    Stefano

  2. duccio il 11 February 2008 alle 10:41 dice:

    Ciao Stefano,
    allora per quanto riguarda il fatto che non ti sia aggiorna la textbox dell’autocomplete dipende dal parziale che usi per renderizzare i risultati… c’è un problema lì magari nel “choosethis“. Per il fatto di volere più campi “hidden” con autocomplete diversi modifica l’helper sostituendo a document.getElementById(”friend_id”) l’object (in teoria se ne hai più di un autocomplete sono diversi) document.getElementById(”#{object}_id”).

    Chiaramente ricorda di modificare anche l’object dell’hidden_field.

    Ultima cosetta se vuoi puoi elimare la funzione getElementsByClassName e mettere il $$(”nome_classe”) del prototype! Spero sia chiara la risposta…
    Duccio

  3. silvio il 24 September 2009 alle 14:49 dice:

    Per rendere l’helper text_field_id_with_auto_complete utilizzabile universalmente basta sostituire al rigo 3 ‘friend_id’ con ’selected_id’ e all’interno della vista sostituire l’hidden field <%= hidden_field :friend, :id %> con <%= hidden_field :selected, :id %>.
    In questo modo l’helper può essere richiamato da qualsiasi vista ed in qualsiasi contesto, però i parametri ritornati dal form sono ovviamente diversi e andranno gestiti accuratamente nel controllore.

Scrivi un commento