Autouzupełnianie w polach formularza. Odc.3.

Sprzężenie dwóch pól z autouzupełnianiem

Skoro już poznałam plugin Autocomplete i odkryłam jak można go wykorzystać do wypełniania dodatkowych pól (co pokazałam w poprzednim odcinku) postanowiłam pójść o krok dalej. Wykorzystać możliwości pluginu do sprzężenia ze sobą dwóch pól typu <input/> korzystających z autouzupełniania. Pisząc po ludzku. Podpowiedzi w drugim polu będą zależały od tego co wybierzemy w pierwszym. Przydatne? Sami zobaczycie.

Dodamy sobie do formularza kolejny wiersz, który będzie zawierał pole <input/> służące do wpisania marki wybrany przedmiot.

<tr>
	<td> Marka </td>
	<td> <input type="text" name="marka" id="marka"> </td>
</tr>

Aby dołączyć do tego pola autouzupełnianie postępujemy dokładnie tak jak poprzednio i definijujemy dla tego pola funkcję autocomplete() dodając do kodu (poniżej definicji funkcji dla pola #urzadzenie) blok:

	$("input#sklep").autocomplete("jq_marka.php", {
		width: 200,
		max: 10,
		selectFirst: false,
		cacheLength: 1
	});

Sprytna tablica i dodatkowy parametr

Jak widać dane do autouzupełniania będą pochodzić ze skryptu jq_marka.php. Gdyby pole #marka nie miało być sprzężone z polem #urządzenie wystarczyłoby w tym skrypcie stworzyć tablicę sklepów i obsłużyć podobnie jak to było z tablicą urządzeń. Chcemy jednak aby lista marek w podpowiedziach zależała od tego jakie urządzenie wybierzemy dlatego stworzę w tym skrypcie tablicę wielowymiarową:

$dane = array('aparat'=>array('kodak','nicon','pentax','sony','canon'),
	'motor'=>array('suzuki','honda','java','panonia','junak'),
	'rower'=>array('giant','author','bMX','alpine','chiba','univega','velo'),
	'samochód'=>array('opel','bmw','ford','honda','lexus','mazda','rover','saab','volvo'),
	'telefon'=>array('samsung','nokia','motorolla','sagem','iphon'),
	'telewizor'=>array('sony','philips','jvc','toshiba','lg','daewoo'));

Purystów przepraszam za pisanie nazw małą literą. Problem polega na tym, że łańcuch znaków przekazywany do skryptu przez parametr ‚q’ jest automatycznie konwertowany do małych liter, więc dla uproszczenia skryptu napisałam wszystko małymi literami.
Taka konstrukcja tablicy pozwala na pobranie dodatkowego parametru, który pozwoli wybrać tablicę podrzędną i w dalszej części skryptu obsłużyć ją w celu wyświetlenia podpowiedzi. Ha… Ale jak przekazać tę dodatkową zmienną? Normalnie to wystarczyłoby w funkcji autocomplete() dodać w opcjach parametr ‚extraParams’ i już. Tylko w naszym przypadku to ma być dynamiczna wartość, sprzężona z poprzednim polem <input/>, więc trzeba to zrobić inaczej. Z pomocą przychodzi funkcja setOptions(), która pozwala zmieniać opcje funkcji autocomplete(). Aby wykorzystać tę możliwość zmodyfikujemy nieco kod funkcji result() odbierającej dane z pola #urzadzenia:

$("input#urzadzenia").result(function(event,arr_urzadz,formatted){
	if(arr_urzadz){
		$("input#grupa").val(arr_urzadz[1]);
		$("td#komunikat").html(arr_urzadz[2]);
		$("input#marka").setOptions({extraParams: {urzadzenie:arr_urzadz[0]}});
		$("input#marka").flushCache();
	}else{
		$("input#grupa").val('');
		$("input#marka").val('');
		$("td#komunikat").html('wybrano wartość spoza listy');		
	}
});
[/code[
Jak widać w przypadku gdy w polu #urzadzenia wybrano pozycję z podpowiedzi zostanie uruchomiona funkcja <tt class="funkc">setOptions()</tt> parametr 'extraParams' do opcji funkcji <tt class="funkc">autocomplete()</tt> pola #marka i nadaje mu wartość pierwszego pola tablicy odebranej przez funkcję <tt class="funkc">result()</tt>. Będzie to nazwa urządzenia wybranego z listy podpowiedzi pola #urzadzenia. 
Poza tym dobrze jest jeszcze wywołać funkcję <tt class="funkc"><a href="http://docs.jquery.com/Plugins/Autocomplete/flushCache">flushCache()</a></tt> dla pola #marka, w celu wyczyszczenia cashe'a. 
W sytuacji, gdy w polu #urzadzenia wpisano wartość spoza podpowiedzi trzeba jeszcze na wszelki wypadek wyczyścić pole #marka. Uf.. Mam nadzieję, że to nie było zbyt skomplikowane. 

<h4>Czerpiemy profit z naszego sprytu</h4>
Nooo. Teraz to już wystarczy tylko odpowiednio obsłużyć ten dodatkowy parametr w skrypcie <tt class="dir">jq_marka.php</tt>. Poniżej pełen kod tego skryptu:

]code lang="php"]
$q = $_GET['q'];
$urzadzenie = $_GET['urzadzenie'];

if (!$q) return;

$dane = array('aparat'=>array('kodak','nicon','pentax','sony','canon'),
	'motor'=>array('suzuki','honda','java','panonia','junak'),
	'rower'=>array('giant','author','bMX','alpine','chiba','univega','velo'),
	'samochód'=>array('opel','bmw','ford','honda','lexus','mazda','rover','saab','volvo'),
	'telefon'=>array('samsung','nokia','motorolla','sagem','iphon'),
	'telewizor'=>array('sony','philips','jvc','toshiba','lg','daewoo'));

if(!$urzadzenie or !$dane[$urzadzenie]){
	echo 'Urządzenie '.$urzadzenie.' spoza listy, brak podpowiedzi'.PHP_EOL;
	return;
}

	$i = 0;
	foreach ($dane[$urzadzenie] as $id => $wartosc) {
		if(preg_match('/^'.$q.'/', $wartosc)){
			echo $wartosc."\n";
			$i++;
		}
	}
	
	if(!$i) echo "marka spoza listy\n";

Pierwsze dwie linijki to odebranie niejawnego parametru ‚q’ i sprytnie przekazanego parametru ‚urzadzenie’. Następnie sprawdzamy, czy parametr ‚q’ ma jakąkolwiek wartość. Jeśli nie (użytkownik nic nie wpisał w polu) skrypt kończy działanie. W przeciwnym razie definiujemy dwuwymiarową tablicę marek, której kluczami są nazwy urządzeń. Sprawdzamy, czy parametr ‚urzadzenie’ ma jakąś wartość (nie ma jeśli użytkownik nie nie wpisał do pola #urzadzenia lub wybrał coś spoza listy podpowiedzi) oraz czy w naszej tablicy istnieje odpowiedni klucz, a więc odpowiednia tablica podrzędna. Tu właśnie mamy profit ze sprytnej konstrukcji tablicy.

Jeśli parametr ‚urzadzenie’ ma nieodpowiednią wartość pojawia się w podpowiedziach odpowiedni komunikat i skrypt kończy pracę. W przeciwnym razie wyciągana jest tablica przypisana do odpowiedniego klucza i w pętli foreach wyświetlane są te z jej wartości, które pasują do ciągu wpisanego przez użytkownika w polu #marka. Prawda, że sprytne? Jak to działa w praktyce można zobaczyć uruchamiając to demo.

I jeszcze jedna uwaga na koniec Jeśli w podpowiedziach mamy polskie znaki to mogą one nieźle namieszać. Ja ćwiczyłam problem przez kilka dni nim opanowałam sytuację. Nie będę się nad tym tu rozwodzić, bo problem opisałam w artykule Polskie znaki w PHP – dramat w czterech aktach.

6 komentarzy do wpisu „Autouzupełnianie w polach formularza. Odc.3.”

  1. + jeszcze jedna uwaga…
    niewiadomo skad w Towim poscie pojawia sie „input#sklep”, gdzie zaden element nie ma id = „sklep”, zmien to na „input#marka”.

    szczerze powiedziawszy ogolnie srednio widze ten pomysl z autouzupelnianiem w drugim polu. trafniej chyba byloby jako drugie pole zrobic po prostu selecta. w ten sposob Twoj przyklad znajdzie zastosowanie w duzo szerszej grupie przypadkow.

    ale ogolnie dobra robota :)
    pozdrawiam
    eL.

  2. Wiesz można i tak. To jest przykład czysto akademicki i można odnieść wrażenie, że jest bez sensu. Jednak ja takie autouzupełnianie robiłam na zamówienie dla formularza z danymi teleadresowymi, które musiały byś zgdodne z danymi z bazy. Bez autouzupełniania selecty byłyby ogromniaste i wobec tego zupełnie bezużyteczne.

    Prosty przykład. W jednym z pól user wpisuje ‚Gorzów’ i zaczyna pisać nazwę ulicy w drugim polu i ma w podpowiedziach jedynie ulice z Gorzowa. Wiesz jak długi byłby select?

    Za znalezienie błędów dziękuję.

Dodaj komentarz

%d bloggers like this: