Słowo wstępu o Autocomplete
Jak już pisałam w artykule Nadszedł czas na jQuery przyszło mi się zmagać z problemem podpowiedzi przy uzupełnianiu formularza. Oczywiście przy małej ilości danych można się pokusić o zastosowanie elementów typu <select> ale gdy w grę wchodzą podpowiedzi pochodzące z bazy danych zawierającej tysiące rekordów a w dodatku chcemy pozostawić użytkownikowi możliwość wpisania czegoś spoza tej puli danych, pozostaje nam już tylko autouzupełnianie.
Z takim właśnie przypadkiem się zetknęłam. W formularzu który przyszło mi obsłużyć były nazwy miejscowości, gmin i ulic z całej Polski. Żaden <select> by tego nie wytrzymał. Dlatego sięgnęłam po plugin Autocomplete dla JavaScriptowego frameworka jQuery
Oczywiście, żeby móc skorzystać z dobrodziejstw tego frameworka i pluginu trzeba je do swojego projektu dołączyć. To akurat najprostsze w naszym zadaniu.
Trzeba ściągnąć paczkę z pluginem Autocomplete i rozpakować w jakimś wygodnym katalogu (niech to będzie na przykład katalog ./jq-ac). W tej paczce jest już samo jQuery. Następnie w nagłówku dokumentu należy dopisać kilka linii:
<script src="./jq-ac/lib/jquery.js" type="text/javascript"></script><script src="./jq-ac/lib/jquery.dimensions.js" type="text/javascript"></script> <script src="./jq-ac/jquery.autocomplete.js" type="text/javascript"></script>
Wpierw dołączamy arkusz stylów zdefiniowanych dla tego pluginu. Oczywiście można go modyfikować, albo stworzyć na jego wzór inny. Następnie dołączamy sam framework jQuery i dwa pliki w których zdefiniowany jest nasz plugin. I już po krzyku.
Uruchamiamy autouzupełnianie
W najprostszym przypadku sposób użycia tego pluginu jest banalny i nie powinien nastręczać problemów nikomu kto choćby odrobinę popróbował JavaScriptu. Aby wyjaśnić w czym rzecz zacznę od skonstruowania formularza:
<form action="" method="post" name="ankieta"><input id="urzadzenia" name="urzadzenia" type="text" /> <input type="submit" value="Akceptuj" /> <table> <tbody> <tr> <th colspan="2">Formularz z podpowiedziami</th> </tr> <tr> <td>Urządzenia</td> </tr> </tbody> </table> </form>
Nic szczególnego. Jedno pole typu <input/>, przycisk <submit/> i wszystko w tabli (nie jest to szczyt elegancji), żeby było równo. Aby podłączyć podpowiedzi do pola <input/> skorzystamy z funkcji autocomplete() W tym celu w nagłówku dokumentu dopisujemy następujący skrypt:
<script type="text/javascript">// <![CDATA[ $(document).ready( function (){ $("input#urzadzenia").autocomplete("jq_urzadzenia.php",{width: 200,max: 10,selectFirst: false, cacheLength: 1}); }); // ]]></script>
W lini nr 4 tego skryptu widzimy wywołanie funkcji autocomplete() dla elementu <input/> o id=”urzadzenia”, czyli dla jedynego elementu tego typu w naszym formularzu. Oczywiście jeśli jest tylko jedne nie musimy go szukać po id, ale lepiej wyrobić sobie taki nawyk. Przecież formularz rzadko składa się z jednego okienka <input/>.
W naszym przykładzie funkcja autocomplete() przyjmuje dwa parametry. Pierwszy z nich definiuje źródło danych, drugi to opcje. O opcjach nie będę się szczegółowo rozpisywać. Nie widzę sensu przepisywania dokumentacji , coś nieco tylko wspomnę o niektórych. Bardziej istotny jest pierwszy parametr. Może to być tablica z danymi, lub jak to jest w naszym przypadku plik, który dane będzie generował dynamicznie. Do takiego skryptu metogą get przekazywany jest niejawny parametr ‘q’, którym jest string wpisany do okienka <input/>. Cała sztuka więc polega na tym, żeby odebrać tę zmienną i sprawdzić które pozycje z listy pasują do wpisanego stringu. Poniżej najprostszy skrypt z pliku jq_urzadzenia.php
<?php $q = $_GET['q']; if(!$q) return; $dane = array('aparat','motor','rower','samochód','telefon','telewizor'); $i = 0; foreach ($dane as $id => $wartosc) { if(preg_match('/^'.$q.'/', $wartosc)){ echo $wartosc.PHP_EOL; $i++; } } if(!$i) echo "urz±dzenie spoza listy\n"; ?>
Skrypt pobiera wspomniany już parametr ‘q’, jeśli z jakiegoś powodu nie ma on wartości to kończy swoje działanie. W przeciwnym razie definiuje listę pozycji podpowiedzi. W tym przykładzie oczywiście statycznie, ale nic nie stoi na przeszkodzie, żeby w tym miejscu dokonać zapytania do bazy i stworzyć dynamicznie tę tablicę. Dlaczego to ma być tablica? Bo łatwo takie dane obsłużyć.
Po zdefiniowaniu tablicy zaczyna się pętla (linie 7-12), która szuka w niej wartości zgodnych wartością przekazaną w do skryptu. Pobiera kolejne łańcuchy znaków z tablicy i sprawdza, czy zawierają one łańcuch wpisany do okienka <input/>. Ja w tym celu wykorzystuję funkcję preg_match(), która korzysta z Perlowych wyrażeń regularnych a w dodatku wymuszam (poprzez zastosowanie metaznaku ^) aby wybrana pozycja zaczynała się od zadanego ciągu. Oczywiście tak skonstruowany skrypt jest czuły na wielkość liter. Można wykorzystać funkcję strtolower() na przykład modyfikując warunek w ten sposób:
if(preg_match('/^'.strtolower($q).'/', strtolower($wartosc))){
ale należy pamiętać, że ta funkcja sprawia poważne problemy w przypadku obecności polskich znaków w stringach i bezpieczniej by było samemu napisać odpowiednią funkcję. Wartości z tablicy, które spełniają zadany warunek (oczywiście może on być skonstruowany zupełnie inaczej, a ograniczeniem są tylko nasze potrzeby i wyobraźnia) są wyświetlane za pomocą funkcji echo. Ważne jest, aby zawsze na końcu znalazł się znak nowej linii, gdyż kolejne linie będą pojawiać się w okienku podpowiedzi jako niezależne pozycje.
W zaproponowanym tu skrypcie znajduje się dodatkowo licznik pozycji pasujących do wzorca. Dodałam go po to, żeby ułatwić zadanie użytkownikowi. Ponieważ jeśli w tablicy nie znajdzie się żadna pozycja pasująca do wzorca zostanie wyświetlony komunikat odpowiedni komunikat w tym wypadku: “urządzenie spoza listy”;
I to już tyle. Jeśli chcesz możesz zobaczyć jak to działa: demo
Lada moment opublikuję kolejny odcinek w którym pokażę co jeszcze można wydusić z tego pluginu.
EDIT (lipiec 2015):
Od dnia publikacji tego tutoriala minęło kilka lat a mimo to są ludzie, którzy chcą z niego skorzystać. Niestety obawiam się, że opisany tu plugin może nie działać z nowszymi wersjami jQuery stąd problemy. Postanowiłam ułątwić ściągnięcie dokładnie tych wersji skryptów jakie zostały użyte w powyższym demo, jak również w dalszych częściach tej serii tutoriali.
jquery.js
jquery.bgiframe.min.js
jquery.autocomplete.css
jquery.autocomplete.js
Ciekawa opcja :)
Nie myślałem, że przez jQuery można coś takiego stworzyć :)
Dzięki za wpis
Oj można jeszcze więcej. Zobaczysz w drugim odcinku :)
Witam
Niestety nie mogę sobie poradzić z pobraniem danych z bazy mysql
robie to w następujący sposób:
while($dane = mysql_fetch_array($wynik))
Przyślij mi na e-mail cały kod w którym pobierasz dane i przygotowujesz je do autouzupełniania. Spróbuję rzucić okiem.
Ciekawy artykuł, oby więcej takich :D
Witam Panią bardzo fajnie to Pani pokazała na przykładzie a ja szukałem autouzupełnienia i proszę tu tak przyjaźnie napisane. Mam też i pytanie do Pani, w przykładzie pokazuje Pani autouzupełnianie na przykładzie danych wprowadzonych ręcznie do skryptu: “jq_urzadzenia.php” moje pytanie brzmi czy mogła by Pani pokazać jak np pobierać dane do autouzupełnienia z bazy danych i to np określone dane z określonych tabel to by było ciekawe bo np jakbyśmy chcieli zrobić taki trik dla kodów pocztowych albo miejscowości to wpisywanie ręcznie wszystkich tych danych do skryptu php było by koszmarem. Pozdrawiam serdecznie
To nic skomplikowanego. Zamiast:
$dane = array(‘aparat’,’motor’,’rower’,’samochód’,’telefon’,’telewizor’);
trzeba napisać:
$dane = moja_funkcja();
No i gdzieś trzeba tę funkcję zdefiniować tak, żeby zwracała tablicę.
Oczywiście tablica kodów pocztowych byłaby koszmarnie długa. Są sposoby, aby pobierać tylko potrzebną część danych. Może faktycznie pokuszę się o stosowny tutorial.
Witam,
szkoda, że tak późno tutaj trafiłem :) W sumie przerobiłem skrypt aby pobierał informacje z bazy (MSSQL). Walczę teraz z kodowaniem :( Niestety mam krzaczki.. problem rozwiązuje częściowo:
header(‘Content-Type: text/html; charset=windows-1250’);
Częściowo ponieważ nie wyszukuje słów rozpoczynających się polskimi literami.. natomiast jak polska litera jest druga i kolejna to nie ma problemu. Przykład:
maść -> i jest ok, prawidłowo sugeruje, prawidłowo rozpoznaje ść, wpisując maść widzi pl znaki
natomiast słowo:
ściana -> nie znajduje, nie daje żadnej sugestii do słów rozpoczynających się od polskich znaków śćźłż itd..
Ma Pani jakiś pomysł na to?
Dziękuję i pozdrawiam !
Ałć… A czemu stosujesz 1250? A feee.
A czytałeś mój artykuł opolskich znakach w php? http://blog.joanna-siwiec.pl/polskie-znaki-w-php-dramat-w-czterech-aktach/65/
Aha, czytałem :) Bazę MSSQL mam w Polish_CI_AS a strona kodowa dla tej kolacji to 1250. Wracając to mojego pytania -> problem nareszcie rozwiązałem. POST a nie GET :) Oto całe rozwiązanie :)
Przepisałem dosłownie cały kod zmieniając tylko nazwę inputa, ścieżki do js i danych (gotowa tabelka w js generowana phpem)
wpisuję:
$(document).ready(
function (){
$(“input#lista_osob”).autocomplete(“osoby”,
{width: 200,max: 10,selectFirst: false, cacheLength: 1});
}
);
i za każdym razem Firebug wypisuje mi: ‘autocomplete is not a function’
A co to jest “osoby”?
nazwa tabeli
wycinek:
var osoby = [
{id:”00136″, imie:”Anna”},
{id:”00145″, imie:”Adam”},
{id:”00118″, imie:”Zygmunt”},
]
Może problem tkwi w deklaracji tej tablicy? A czy to nie powinno być bez cudzysłowa?
w przykładach http://jquery.bassistance.de/autocomplete/demo/ był taki kod, ale nie za bardzo go rozumiem zwłaszcz formatItem :
$(“#thickboxEmail”).autocomplete(emails, {
minChars: 0,
width: 310,
matchContains: true,
highlightItem: false,
formatItem: function(row, i, max, term) {
return row.name.replace(new RegExp(“(” + term + “)”, “gi”), “$1“) + “Email: <” + row.to + “>”;
},
formatResult: function(row) {
return row.to;
}
});
polami w tabeli emails były ‘to’ i ‘name’
Na temat formatItem naskrobię w wolnej chwili, ale tymczasem zwróć uwagę, że nazwę tablicy wstawia się bez cudzysłowu.
Kombinowałem już na wszelkie możliwe sposoby i nadal nic, a w dodatku muszę to mieć do wieczora :/ Może jest ktoś w stanie mi wyjaśnić gdzie mam błąd? (Uwaga strona stoi na powolnym serwerze)
http://czacki.edu.pl/~janusz/af_test/panel_af/panel_af.php?czynnosc=dodawanie&tabela=rel_os_przedst_poz&zakl=baza&krok=1
Odkryłem co było nie tak. Dwa razy wrzucałem samo jQuery. :P
Te pierwsze trzy kody od góry mają sie znależć w jednym pliku index.php?
Bo nie bardzo wiem gdzie mam te poszczególen bloki kodu wpisać. prosze o pomoc
Formularz ma się znaleźć na tej stronie na której chcesz mieć formularz :P a skrypty powinny być na tej samej stronie tylko w sekcji <head>
Witam,
Odnośnie Pani wpisu : To nic skomplikowanego. Zamiast:
$dane = array(‘aparat’,’motor’,’rower’,’samochód’,’telefon’,’telewizor’);
trzeba napisać:
$dane = moja_funkcja();
No i gdzieś trzeba tę funkcję zdefiniować tak, żeby zwracała tablicę
Czy mogę prosić o wskazówki
Pozdrawiam
A nie ma ich w następnych artykułach?
Witam, Niestety nie znalazłem w następnych artykułach. Chodzi mi o dopisanie funkcji pobierającej dane z bazy i nie wiem jak się do tego zabrać
No rzeczywiście. Dawno już pisałam te artykuły i nie pamiętałam co tam dalej było.
To naprawdę proste. Zamiast linijki
$dane = array(‘aparat’,’motor’,’rower’,’samochód’,’telefon’,’telewizor’);
Trzeba wstawić wywołanie skryptu, który pobierze dane z bazy i zwróci stosowną tablicę. Definiujesz sobie taki skrypt, w którym będzie funkcja potrafiąca połączyć się z bazą (mysql_connect), wykonać na niej zapytanie SQL (mysql_query) i przetworzyć je do postaci potrzebnej tablicy (mysql_fetch_row). Skrypt dołączasz za pomocą include i już. Prawdę mówiąc nie bardzo rozumiem z czym masz problem. Może więcej napiszesz?
Ok, zrobię tak jak napisałaś i dam znać ( raczkuję w php i może stąd banalny problem )
Zamiast – $dane = array(‘aparat’,’motor’,’rower’,’samochód’,’telefon’,’telewizor’);
wstawiłem :include ‘connect.php’;
include ‘query.php’;
a moje query wygląda tak :
Niby ok , ale tylko pokazuje pierwszą wartość z bazy ;)
query :
$zapytanie = “SELECT id FROM adres”;
$wynik = mysql_query($zapytanie);
$dane = mysql_fetch_row($wynik);
Bo linijka $dane = mysql_fetch_row($wynik); bierze tylko pierwszy rekord. Trzeba to zrobić w petli tak jak w manualu pokazują:
http://pl2.php.net/manual/en/function.mysql-fetch-row.php#81309
Czyli:
while($row=mysql_fetch_array($wynik ))
$dane[] = $row[‘id’];
while($row=mysql_fetch_row($wynik )) $dane[] = $row[0];
Dziekuje – jest ok
A u mnie skrypt php wcale nie otrzymuje parametru. Gdy dodam jakąś zmienną $q w środku skryptu to pokazuje tylko pasujące do niej podpowiedzi, a parametru nie widzi.
Nie sądzę, żeby nie znając kodu, udało mi się zgadnąć, dlaczego tak się dzieje.
Mam pytanko, może laickie ale i tak je zadam. Skoro tak się udało rozpisać o tablicach to może gotowy przykładzik na bazę? Ten tu podany zawiera tylko fragment rozsiany, a tak jak to tu było zaznaczone, bardziej się przyda przykład z bazą zawierającą tysiące rekordów niż z tablicą która ma ich kilka. Czy byłaby taka możliwość by załączyć kompletny skrypt na bazę? Za cierpliwość w nadmiarze z góry dziękuję
No nie żartuj. Przecież nawiązanie połączenia z bazą, wysłanie zapytania, odebranie rekordów i wrzucenie ich w pętli do tablicy to szkolne zadanie. Znajdziesz to w każdym podręczniku do PHP. A podpowiedzi sa w starszych komentarzach. Gotowca nie będę pisać. To by było mało wychowawcze, a ja mam belferską naturę ;)
Kłopot mam w tym, że zakładając, iż tabela ma dwa rekordy: id, nazwisko – chciałbym z inputa odebrać id (pomimo, że uzupełniane nazwisko), i tu mam zonka. Jak z tego odebrać zmienną? Starałem się dodać tą zmienną w zapytaniu do bazy ale poległem. Pomijając fakt, że przy Polskich ogonkach najczęściej zaprezentowany skrypt omija te rekordy. Czy na prawdę nie da się tego jakoś obejść. Heh skoro belferska natura – to pytam :)
I bardzo dobrze, że pytasz. Lubie dociekliwych studentów, nawet jeśli są niecierpliwi ;)
Sądzę, że podpowiedź w związku z pierwszym pytaniem znajdziesz w drugim odcinku tej serii:
http://blog.joanna-siwiec.pl/autouzupelnianie/62/
Natomiast jeśli chodzi o polskie znaki, to tez się trochę z tym zmagałam i to co odkryłam opisałam tu:
http://blog.joanna-siwiec.pl/polskie-znaki-w-php-dramat-w-czterech-aktach/65/
Życzę przyjemnej lektury.
A ja mam niezłą zagwozdkę, bo chciałbym połączyć autouzupełnianie z dynamicznie generowanymi polami formularza z tej strony http://antczak.org/2009/10/dynamiczne-formularze-z-uzyciem-jquery/ , ale nie mam pomysłu na id.
Ale to co? Mamy Ci wymyślić jakie masz nadać ID?
W twoim przykładzie id jest przypisane na stałe, a co w przypadku gdy id jest generowane dynamicznie, i nie mogę użyć $(“input#urzadzenia”)
To wtedy trzeba pokombinować. Nie sprawdziłam, ale spróbowałabym najpierw wykryć który element został kliknięty, odczytać jego ID a następnie zastosować do niego funkcję autocomplete.
No i pokombinowałem i bardzo obszerny artykuł na temat autouzupełniania, poszerzający to co jest zawarte tutaj można znaleźć pod adresem http://dev.baczyk.net/2009/12/24/jquery-autocomplete-magiczne-podpowiedzi/
W moim skrypcie zaciągane są informacje z bazy danych, jednakże kiedy zapytanie nic nie znajdzie, wyświetla się komunikat:
Warning: Invalid argument supplied for foreach() in
on line 15
Poniżej kod. Bardzo proszę o pomoc
$wartosc)
{
if(preg_match(‘/^’.strtoupper($q).’/’, strtoupper($wartosc)))
{
echo $wartosc.PHP_EOL;
$i++;
}
}
if(!$i) echo “Brak danych w bazie…\n”;
include (“../../disconnect.php4”);
?>
No to może sprawdziłbyś w manualu jaki Typ zwraca Ci funkcja kiedy nie znajdzie nic w bazie a jaki typ powinna mieć zmienna którą chcesz przeanalizować za pomocą foreach() ]:-> Polecam tez podstawowy kurs angielskiego, albo przynajmniej korzystanie z jakiegoś translatora, bo komunikat w warningu mówi ci wszystko.
A jak przekazać np. dwie zmienne przez autocomplete?
Chodzi mi o kolejny parametr wykorzystywany w zapytaniu do bazy. Niestety kiedy podaję drugi wykorzystując zmienne, skrypt przestaje działać.
Przepraszam nie przeczytałem.
extraParams: {‘check_id’:$(‘#check_id’).val()},
i wszystko jasne.
Jaq
jednak malutka drobnostka, której poświęciłem już więcej czasu, niż zajęło mi całe zamontowanie tego skryptu na swoją stronę, a dalej nie mogę znaleźć rozwiązania: jak wyrównać propozycję do lewej (zamiast wycentrowania na liście propozycji). Tak jak jest to zrobione tutaj: http://jquery.bassistance.de/autocomplete/demo/
Będę bardzo wdzięczny za podpowiedź :).
świetny tutorial ale mam pytanie jak tą zmienną wartość przekazać dalej. chodzi mi o coś takiego że z bazy danych pobieram nazwy drużyn przez podpowiedzi i po kliknięciu pokaż wyświetlam wybrany rekord
Hej, fajnie to ci to wyszlo,
podpowiesz co mam zle ?
cały czas: Notice: Undefined index: q
$q = $_GET[‘q’];
if(!$q) return;
$q = array(‘select count(*) from akt where nr_akt like (‘%”.$q.”%’)’);
$i = 0;
foreach ($q as $id => $wartosc) {
if(preg_match(‘/^’.$q.’/’, $wartosc)){
echo $wartosc.PHP_EOL;
$i++;
}
}
if (mysql_num_rows($q)>0) {
echo ‘jest’;
}
else
{
echo ‘niema’;
}
Musiałbyś pokazać większy kawałek kodu. Może wyślij mi na e-mail?
Hej. Mam problem, bo mi skrypt nie działa.. wrzuciłem wszystko tak jak u Ciebie, ale nadal wpisując w pole formularza, nie otrzymuje żadnej podpowiedzi.
Coś musiałeś jednak zrobić inaczej, bo jak możesz się przekonać u mnie działa :)
Witaj
z tego co widzę jeśli w pliku jq_urzadzenia.php są nagłówki to wczytuje je do listy z inputa …. dziwne.
Nie wyświetlami się pierwsza litera tak jak w przykładzie u Ciebie .
Pozdrawiam
Wszystko mam spisane identycznie.