niedziela, 3 kwietnia 2011

Rails autocomplete - uruchamianie akcji po kliknięciu

     Pomiędzy tysiącami dodatków do Ruby on Rails znajduje się kilka, z których korzystamy praktycznie zawsze. Jednym z nich jest "autocomplete". Umożliwia on dynamicznie uzupełnianie zawartości pola tekstowego treścią z bazy danych. Użyteczne, proste w obsłudze i łatwo implementowalne w programie.
Przy czym stwierdzenie "łatwo implementowalne" dałem tak troszkę na wyrost. Pierwsze schody już na samym początku: dokumentacja. Na stronie pluginu otrzymujemy przykład prostej konfiguracji i linki do szczegółowej dokumentacji. Radość? Przedwczesna! Ta prosta konfiguracja opisywana na stronie jest o tyle szybko implementowalna, o ile nigdy nie wystarczająca do Twojego projektu, który akurat piszesz. Natychmiast więc klikasz w linki aby uzyskać szczegóły API, przykłady kodu i inne tego typu, wydawało by się, duperele. Co się okazuje? Linki prowadzą na strony scriptaculous, które nie tylko, że niczego nie rozwiązują, to jeszcze wstydliwie się rozjeżdżają. Jeśli nie wiesz o czym piszę, to kliknij sobie tam na te linki. Wstyd? Mi też się tak wydaje. Nie podaję więc ich tutaj. Podaję zaś link do działającej dokumentacji scriptaculous. Nie pytaj mnie dlaczego tak jest? Nie wiem. Tysiące programistów pytających się o to samo w sieci też nie wie. Cisną się na usta epitety :-) ale nie z takimi rzeczami dawaliśmy radę :-)

     Oprócz bardziej szczegółowej konfiguracji autocomplete natychmiast szuka się rozwiązania automatycznego jego zadziałania. Bo umówmy się, że autouzupełnianie pola tekstowego, to zazwyczaj jest tylko pretekstem do używania autocomplete jako szybkiej wyszukiwarki. Czyli, na przykład, jeśli wyszukujesz kandydata po nazwisku i imieniu (kandydata, bo w naszym programie do rekrutacji HR mówimy o kandydatach na stanowisko pracy) szukając Kowalskiego Jana, wpisujesz powoli "Kow..." i spodziewasz się, że system podpowie Ci Kowalskiego, Kowalewskiego, Kowalczyka i innych na "Kow...". Z pokazującej się listy klikasz na Kowalskiego i hyc! Przeskakujesz do widoku szczegółowych danych Kowalskiego. Denerwowało by Cię gdybyś kliknąwszy Na Kowalskiego zobaczył jak pole tekstowe wypełnia się jego nazwiskiem i imieniem, a Ty musisz dodatkowo naciskać przycisk "szukaj", który może znajdować się, na przykład, gdzieś daleko na dole formularza.
Szukasz więc rozwiązania tej trywialnej i, co tu dużo mówić, jakże pospolitej potrzeby. I co Cię spotyka? Schody. I to schody całkowicie niezrozumiałe. Przecież to, czego szukasz jest potrzebne praktycznie zawsze! Dlaczego autor pluginu tego nie zamieścił? Potem Ci opadają ręce: autor pluginu niczego nie zamieścił! Dupek skończony nie zamieścił nigdzie dokumentacji do API, przykładów, a dodatkowo wprowadza w błąd podając wstydliwe linki. Chwilkę siędzisz wkurzony (delikatne słowo) z opadniętymi rękami. Potem odpalasz google i próbujesz najróżniejszych fraz zgadując jak inni mogli o to samo zapytać. Potem modlisz się aby wpisana przez Ciebie fraza była właśnie tą, na którą znajdzie się odpowiedź. Potem przekopujesz setki rozwiązań i wciąż nie znika Ci z twarzy wyraz niedowierzania jak inni to implementują...
Bo na przykłąd tak:

<%= text_field_with_auto_complete :candidate, :name,
                                  {:onchange => "#{remote_function(:url  => {:action => "update_text_fields"},
                                   :with => "'surname='+value")}", :size => 18},
                                  {:min_chars => 3, :skip_style => true} %>
a później gdzieś w kontrolerze:
def update_text_fields
  .
  # implementacja
  .
end 
Prawie działa, tylko że przechwytuje to, co użytkownik wpisał, a nie tę znalezioną już wartość.
To może tak:
<%= text_field_with_auto_complete :candidate, :name,
                                  {:size => 18},
                                  {:after_update_element =>
                                               "function(element,value){" + remote_function(
                                   :url => {:action => :update_text_fields},
                                   :with =>"'surname='+element.value") + "}",
                                   :skip_style => true, :method => :get} %>
To działa, ale ma zastosowanie tylko do tego, aby funkcja "update_text_fields" mogła Ajaxem dynamicznie wypełnić jakąś zawartość na stronie bez przeładowania. Uwaga! W powyższym przykładzie nie jest zaimplementowana ta funkcjonalność.


Aż w końcu, zamiast dalej szukać, zaimplementuj to proste i łatwe rozwiązanie:
<%= text_field_with_auto_complete :candidate, :name,
                                  {:size => 18},
                                  {:after_update_element => "candidateNameSearch"} %>
Gdzie "{:size => 18}" ustawia wielkość pola.
Dodajesz jeszcze tylko króciutką funkcję JavaScript:
function candidateNameSearch(element, value) {
  window.location.href = '/candidates/update_text_fields?surname='+element.value;
}
I wszystko! Działa. Praktyczne, szybkie, łatwe, zdrowe.
Miłej zabawy.

Brak komentarzy:

Prześlij komentarz