Praktyczne wprowadzenie do JavaScript #15

Często, kiedy wypełniamy różnorakiej maści formularze, zawierające pola z limitem znaków maxlength, spotykamy się z sytuacją, kiedy po przekroczeniu ograniczenia, jesteśmy automatycznie kierowani do następnego pola. Piętnasty odcinek kursu JavaScript pokaże, jak zrobić coś takiego przy pomocy około 20 linijek kodu JS.

Screencast z tego odcinka znajdziecie tutaj, natomiast przykład na żywo tutaj.

O użyteczności tego rozwiązania można co prawda dyskutować, jednak w wypadku rozbudowanych formularzy, mozolne naciskanie klawisza tab może okazać się zbyt pracochłonne i irytujące jednocześnie.

Pierwszym krokiem w budowie skryptu obsługującego opisaną wyżej funkcjonalność, będzie stworzenie prostego szablonu HTML. Oto on:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="pl-PL">
<head>
<title>Strona z formularzem</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />

<!-- Nasz kod Javascript: -->

<script type="text/javascript">

</script>

</head>
<body>
	<div>
		<form name="formularz">
		  <input type="text" name="jeden" maxlength="5" />
		  <input type="text" name="dwa" maxlength="5"  />
		  <input type="text" name="jeden2" maxlength="5" />
		  <input type="text" name="dwa2" maxlength="5"  />
		</form>
	</div>
</body>
</html>

Przyjrzyjmy się teraz temu, jak działać będzie skrypt. Otóż podczas wypełniania danego elementu, który będzie posiadał atrybut maxlength, specjalna funkcja sprawdzi, czy ilość wpisanych znaków jest równa wartości maxlength. Jeśli tak, skrypt postara znaleźć się następny input w kolejce i przejdzie właśnie do niego. Czyli: jeśli musimy wpisać w pole kod pocztowy, po wpisaniu 6 znaków np. 33-333, skrypt rozpozna, że powinniśmy przejść do następnego pola.

Jak zapewne kojarzysz, aby sprawdzić w trakcie wpisywania, ile znaków zostało już użytych, należy obdarzyć input zdarzeniem onkeyup po załadowaniu dokumentu HTML, a następnie w specjalnej funkcji odwołać się do właściwości value.length. Zróbmy to, wykorzystując najpierw starą metodę window.onload.


	window.onload = function()
	{
		elements = document.forms['formularz'].elements;
		for (var i = 0;i < elements.length ; i++ )
		{
			if (elements[i].getAttribute('maxlength') < 50)
			{
				
				elements[i].onkeyup = Sprawdz;
			}
			
		}
	}

Jak widać, pobraliśmy do zmiennej elements wszystkie elementy formularza o name="formularz". Następnie w pętli for{}, jak zwykle zresztą, sprawdzamy, czy dany element ma zdefiniowany atrybut maxlength mniejszy niż 50 znaków. Dlaczego nakładamy to ograniczenie? Całe sedno tkwi w przeglądarce Internet Explorer. Kiedy nie zdefiniujemy w ciele HTML atrybuty maxlength, w IE JS pobierze domyślną wartość dla inputa, jaką jest bardzo duża liczba 2147483647. W Operze i FF będzie ona wynosiła null, czyli zero, nic. Warto więc się zabezpieczyć.

Na samym końcu, jeśli podany warunek będzie prawdziwy, czyli limit znaków dla danego elementu będzie mniejszy od 50, nadajemy mu zdarzenie onkeyup w postaci funkcji Sprawdz.

Funkcja Sprawdz będzie liczyła znaki podczas ich wpisywania z klawiatury w danym inpucie. Kiedy ich liczba będzie równa limitowi przypisanemu dla danego pola, uruchomi się funkcja Next. Znajdzie ona nam następny element w kolejce, który trzeba aktywować. Zabierzmy się więc za ich implementację.

function Sprawdz()
	{
		if (this.value.length == this.getAttribute('maxlength'))
		{
			active = this.name;
			Next();
		}

	}

Warunek

if (this.value.length == this.getAttribute('maxlength'))

sprawdza, czy liczba wpisanych znaków (this.value.length) jest równa wartości atrybutu maxlength (this.getAttribute('maxlength')). Zauważ, że użyliśmy tutaj słówka this. Oznacza to, że odwołujemy się do biężącego elementu, któremu przypisaliśmy funkcję Sprawdz jako zdarzenie. Jeśli więc przypisujemy jakiemuś elementowi zdarzenie, onclick, onmouseon i inne, w funkcji, która odpowiada za ich obsługę, możemy bez problemu używać this jako odnośnik do elementu, któremu dana funkcja została przypisana jako te zdarzenie. Popatrzmy:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="pl-PL">
<head>
<title>Strona z formularzem</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />

<!-- Nasz kod Javascript: -->

<script type="text/javascript">
	window.onload = function()
	{
		document.getElementById('div').onclick = Test;
	}
	function Test()
	{
		alert(this.id);
	}

</script>

</head>
<body>
	<div id="div">
		cos tam
	</div>
</body>
</html>

W podanym przykładzie, przypisaliśmy zdarzenie onclick elementowi <div>. Jak widzimy, po kliknięciu wykona się przypisana temu zdarzeniu funkcja Test. Jak się przekonujemy, pokazuje ona id elementu, na który kliknęliśmy. W tym wypadku w okienku ujrzymy wartość div. Tak więc, jak widać, nie musimy pisać czegoś takiego, by dostać się do właściwości elementu:

	function Test()
	{
		alert(document.getElementById('div').id);
	}

Czy też

	function Test()
	{
		alert(document.getElementById('div').innerHTML);
	}

i tak dalej. Wystarczy this.

Wracając do naszej funkcji Sprawdz, jeśli warunek będzie prawdzimy, wykona się następujący kod:

active = this.name;
Next();

Pierwsza linijka mówi nam, że przypisujemy do zmiennej o nazwie active wartość atrybutu name elementu, w którym wykorzystaliśmy limit i z którego chcemy przejść do następnego inputa. Jeśli więc wykorzystaliśmy limit w polu o nazwie jeden, zmienna acitve będzie miała wartość jeden. Zmienna active i jej wartość, będzie nam pomocna we funkcji Next, ta więc musimy ją też zdeklarować poza wszystkimi funkcjami, tak, by była dostępna dla każdej z nich.

 <script type="text/javascript">
	var active;

Sprawa załatwiona. Wracając znów do Sprawdz, ostatnia linijka - Next(); wywołuje po prostu funkcję Next, aby ta znalazła następne pole i aktywowała je. W zasadzie to ostatni element układanki, zajmijmy się nim.

Jak działać będzie funkcja Next? Otóż "przejedziemy się" znów po wszystkich elementach naszego formularza przy pomocy pętli for{}:

	function Next()
	{
		elements = document.forms['formularz'].elements;
		for (var i = 0;i < elements.length ; i++ )
		{
			
		}
	}

Następnie, musimy znaleźć w pętli pole, w którym właśnie wykorzystaliśmy limit znaków. Jak wiemy, zmienna active przechowuje jego nazwę, więc dlaczego nie porównać jej z nazwą pola w pętli?

	function Next()
	{
		elements = document.forms['formularz'].elements;
		for (var i = 0;i < elements.length ; i++ )
		{
			if (elements[i].name == active)
			{
			}
		}
	}

Jeśli warunek elements[i].name == active będzie prawdziwy (czyli znaleźliśmy wśród elementów aktywne pole), musimy odwołać się do elementu następnego w kolejce.

	function Next()
	{
		elements = document.forms['formularz'].elements;
		for (var i = 0;i < elements.length ; i++ )
		{
			if (elements[i].name == active)
			{	if (elements[i+1])
				{
					elements[i+1].focus();
				}
			
				
			}
		}
	}

Jeśli wiemy, że w tablicy o nazwie elements mamy jakąś liczbę elementów formularza, do których odwołać możemy się tak: elements[liczba], przejście do następnego elementu polegać będzie po prostu na zwiększeniu liczby o jeden: elements[liczba+1]. W tym wypadku mamy elements[i+1]. Przy pomocy:

if (elements[i+1])

Sprawdzamy natomiast, czy istnieje takie pole. Jest to przydatne, biorąc pod uwagę, że aktywne pole może być ostatnie, więc w takim wypadku ujrzelibyśmy błąd.

.focus() to natomiast funkcja charakterystyczna dla elementów formularzy, która je aktywuje.

Całość wygląda tak:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="pl-PL">
<head>
<title>Strona z formularzem</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf8" />

<!-- Nasz kod Javascript: -->

<script type="text/javascript">

	var active;
	
	function Sprawdz()
	{
		if (this.value.length == this.getAttribute('maxlength'))
		{
			active = this.name;
			Next();
		}

	}
	function Next()
	{
		elements = document.forms['formularz'].elements;
		for (var i = 0;i < elements.length ; i++ )
		{
			if (elements[i].name == active)
			{	if (elements[i+1])
				{
					elements[i+1].focus();
				}
			
				
			}
		}
	}
	window.onload = function()
	{
		elements = document.forms['formularz'].elements;
		for (var i = 0;i < elements.length ; i++ )
		{
			
			if (elements[i].getAttribute('maxlength') < 50)
			{
				
				elements[i].onkeyup = Sprawdz;
			}
			
		}
	}

</script>

</head>
<body>
	<div>
		<form name="formularz">
		  <input type="text" name="jeden" maxlength="5" />
		  <input type="text" name="dwa" maxlength="5"  />
		  <input type="text" name="jeden2" maxlength="5" />
		  <input type="text" name="dwa2" maxlength="5"  />
		</form>
	</div>
</body>
</html>

W ten sposób osiągnęliśmy zamierzony cel. Zapewne spytasz, co z addEventListener? Impementację tej funkcji, zgodnej z DOM, weźmiemy na warsztat w następnym odcinku.

Komentarze

1

A będzie więcej o focusie? I hope so :)

2

Witam myślę, że można było wspomnieć jeszcze o możliwości wcześniejszego zakończenia pętli for a mianowicie o break:
function Next()
{
elements = document.forms['formularz'].elements;
for (var i = 0;i < elements.length ; i++ )
{
if (elements[i].name == active)
{ if (elements[i+1])
{
elements[i+1].focus();
break;
}

}
}
}

Daje nam to możliwość oszczędzenia czasu przez przerwanie pętli kodu w momencie gdy znajdziemy szukany element a liczba pozostałych do przeszukania elementów jest duża.

Czytam wprowadzenie od początku – może będzie dalej ;-).

LUK
3

…tutaj podobnie jak w poprzedniej lekcji, napisałeś: „Zauważ, że użyliśmy tutaj słówka this. Oznacza to, że odwołujemy się do biężącego elementu, któremu przypisaliśmy funkcję Sprawdz jako zdarzenie. „. No niestety nie działa to zawsze poprawnie, metoda nie ma dostępu do obiektu i zgłasza „this.value is undefined”. Wydaje mi się, że ta wartość powinna być przekazywana jako parametr w metodzie i wtedy zawsze zadziała.

pozdr,

Dodaj komentarz

Dozwolone tagi: <blockquote>, <code>, <strong>