Bevezetés
Az előző blogbejegyzésem végén felsoroltam
néhány olyan Javascript csomagot, amelyeket tipikusan a validáció miatt
hoztak létre. Természetesen közel sem az összeset soroltam ott fel, de
most azok közül fogok megismerni egyet példákon
keresztül. A célom az, hogy az így kipróbált osztálykönyvtár helyett
akár másféléket is tudjatok majd alkalmazni, tehát egy megalapozó tudást
szeretnék adni ahhoz, hogy bármilyen más Javascript osztálykönyvtárat
ezután már sikerrel tudjatok beépíteni a saját alkalmazásotokba.
Elöljáróban még annyit megjegyeznék (ezt már a bejegyzés megírása után írom),
hogy én részletesebben megnéztem még néhány osztálykönyvtárat, de -
talán a túl magasa igényeim miatt? - mindegyikben találtam valami olyan
kivetnivalót, amely miatt inkább nem javasolnám a használatát. Viszont
itt alább egy olyat vizsgálok és mutatok be részletesen, amelynek a
működtetése egyszerű, logikus, sokrétű, úgyhogy ennek a használatát
javasolnám nektek.
A vizsgálati alany: Just Validate
Azt
mondják, a külső megfog, a belső megtart, emiatt én legelőször a FormValidation.io-val
próbálkoztam (a külső megfogott, de aztán a belső elég gyorsan
elengedett...), viszont ez olyan egyéb osztálykönyvtárakat is igényel,
amiket én első körben nem akartam használni (jQuery, Bootstrap -
ráadásul ezek régebbi verziószámaival működik együtt), úgyhogy mivel
csak a lényegre, a validációra akartam koncentrálni, emiatt módosítottam
a választásomat. Megpróbálkozok egy olyannal osztálykönyvtárral, aminek
a weboldala design-os és
megbízhatónak tűnik, fejlesztik is (Github legutóbbi commit dátumából
lehet erre következtetni), valószínűleg egyszerű is, ez a Just Validate - szintén beszédes - névre hallgat.
Szerencsére van dokumentációja
is a működő példák mellett, úgyhogy ez alapján fogok haladni, de
természetesen úgy, hogy a
saját Laravel projektembe építem bele továbbra is az űrlap validációját.
Az előző bejegyzésben azt kértem a végén, hogy aki gyakorolni szeretne,
csinálja meg a create-ek után az edit nézetek validálását is. Én ezt
most már a validációs osztálykönyvtárak segítségével fogom megtenni, az
utasok szerkesztési űrlapjával fogom kezdeni, majd utána a repülőjáratok
létrehozási és szerkesztési nézetével fogom folytatni, de előtte
mindenképpen
szükség van a Just Validate importálására.
Just Validate: telepítés és használat
A "telepítéshez"
többféle módszert is tudok használni: npm vagy yarn csomagkezelővel
is
működhet (lásd majd később ezt), de én inkább először csak betöltöm a
Just Validate legfrissebb
verzióját CDN-en (Content Delivery Network szolgáltatáson) keresztül az
oldalamra. Ezek a CDN-ek azért jók, mert olyan csomagokat tárolnak,
amiket rengeteg webprogramozó használ és nagyon gyors elérést
biztosítanak hozzájuk, így nem kell a saját alkalmazásunkba telepíteni a
csomagot és figyelni a frissítéseire (mindig nagyon gyorsan elérhetőek
ezek a csomagok a távoli szerveren). Persze a másik telepítési módnak is
vannak előnyei, de ezekről majd később. Én most, mivel először a CDN-es
használata mellett
döntöttem, innentől kényelmes megoldásként azt választhatnám, hogy a
script-et simán beírom a layout.blade.php fájlom head részébe, és akkor
mindenhol elérhető a validáció. Ezt én mégsem javasolnám, mert érdemes
figyelni az optimalizálásra is: olyan aloldalunkon, ahol nincs szükség a
validációra, ott ne töltsük be a validációs fájlt. Inkább csak a
helyőrzőjét csináljuk meg a layout head részében, így:
@stack('head-scripts')
Amelyik "alnézetben"
pedig alkalmazni szeretnénk ezt a fajta validációt, ott majd
importáljuk a szükséges fájlt, például a passengers / edit.blade.php -n
belül így:
@push('head-scripts')
<script src="https://unpkg.com/just-validate@latest/dist/just-validate.production.min.js"></script>
@endpush
Ahogy említettem, ez a Just Validate legutóbbi (vegyük észre a linkben a "latest" kulcsszót, ami majd valós verziószámmá fog átalakulni betöltéskor), élesben használatos (erre utal a "production" kulcsszó a linkben), minimalizált és optimalizált Javascript kódját tartalmazza.
A
szerkesztési űrlap nagyjából rendben van, csak egyetlen dolgot bővítek
ki: a form nyitó tag-jéhez hozzáadok egy id attribútumot:
id="passengerEditForm"
Ezzel
fogok majd tudni hivatkozni az űrlapra a validáláshoz. Tegyük is ezt
meg: egy újabb blokkot adunk hozzá a fájlhoz, ami a tényleges validálást
hajtja végre:
@push('scripts')
<script>
const validation = new window.JustValidate('#passengerEditForm');
validation
.addField('#utasneve', [
{
rule: 'required',
errorMessage: 'Név mező megadása kötelező!',
},
{
rule: 'minLength',
value: 10,
errorMessage: 'A Név mező legalább 10 betűből álljon!',
},
{
rule: 'maxLength',
value: 50,
errorMessage: 'A Név mező legfeljebb 50 betűből álljon!',
},
])
.addField('#email', [
{
rule: 'required',
errorMessage: 'E-mail mező megadása kötelező!',
},
{
rule: 'email',
errorMessage: 'Az e-mail érvénytelen!',
},
{
rule: 'maxLength',
value: 100
},
])
.onSuccess((ev) => {
ev.target.submit();
}
);
</script>
@endpush
Az iménti kód annyit csinál, hogy létrehoz egy
JustValidate objektumot, amit hozzáköt a passengerEditForm id-jú
űrlapunkhoz. Utána pedig ehhez az objektumhoz szép sorban hozzáadogatjuk
a mezőinket, szintén azonosítóval, ahogy a CSS-ben megismertük
(#utasneve, #email). Egy tömbben pedig a mezőkhöz hozzáadjuk a
szabályokat, például, hogy kötelező (required) volt a kitöltése, vagy a típusának
e-mailnek kell lennie, de ugyanezt megtehetjük még a minimális/maximális
hosszúsággal is stb. A szabályokat, ha "errorMessage" nélkül definiálom,
akkor angolul fogja kiírni az alapértelmezett hibaüzenetet
(kipróbálhatjuk úgy is majd, hogy az iménti kód szerinti űrlapon több mint 100
karakter hosszú e-mail címet próbálunk megadni, ekkor angol hibaüzenetet fogunk kapni, hiszen ahhoz nincsen errorMessage-ünk).
Teszteléskor a szabályok megszegését nem fogja jelezni az oldal rögtön, csak a Frissítés (küldés) gomb megnyomásakor. Tipp:
teszteléshez megint érdemes lehet az űrlapon az utas neve és e-mail
címe (input) mezőinél kitörölni a validációs elemeket (required,
minlength, maxlength), hogy ténylegesen csak a Just Validate-es
Javascript-es validálást tudjuk tesztelni.

A Frissítés gomb megnyomása után
azonban már "élővé" válik a validáció, és ha például ilyen hibaüzenetet kapunk, mint az
iménti képen is látszódik, akkor ha 10 karakternél hosszabb nevet írok
be, akkor automatikusan eltűnik ez a hibaüzenet, de ha visszatörlöm a
nevet néhány karakteresre, akkor ismét megkapom ezt a jelzést. Ha pedig
teljesen kitörlöm a nevet, akkor megkapom a "Név mező megadása
kötelező!" szövegezésű hibaüzenetet.
Persze, ha csak ilyen
egyszerű validációkat szeretnénk használni, akkor nem feltétlenül lenne
szükség külső osztálykönyvtár alkalmazására, azonban ennél sokkal
komplexebb lehetőségeink is vannak szabályok létrehozására a Just
Validate segítségével. A folyamat ugyanez lehetne, mint amit az előbb
felvázoltam, csak sokkal specifikusabb szabályokat tudnánk még
létrehozni, akár még a validációs CSS stílus szabályok megadására is
lehetőségünk van, de a többnyelvű figyelmeztető üzenetek meghatározására
is egyszerűen képesek vagyunk általa... Fontosnak tartom még
megemlíteni, hogy a fájlfeltöltésnél és a dátumok ellenőrzésénél is jó
szolgálatot tehet nekünk a Just Validate osztálykönyvtára (ez utóbbival fogjuk folytatni).
Dátumellenőrzéshez a Laravel-es háttér összerakása
Próbáljuk is
ki a dátumok ellenőrzését és kezelését, mivel ezekkel sok probléma
szokott lenni és talán nem árthat egy kis gyakorlás sem... Térjünk rá a
repülőjáratokra (flights) és adjunk hozzá az adatbázishoz két új mezőt:
php artisan make:migration add_dates_to_flights_table
Azt ellenőrizzük majd, hogy a
tervezett érkezés dátuma nem lehet korábbi vagy megegyező, mint a tervezett indulás
dátuma, ehhez a két mező hozzáadása az up() metódusban (tudom, hogy
vannak már hasonló mezőink, de most ezeket a tervezett értékeket fogom
használni a validációhoz):
$table->timestamp('scheduled_departured_at');
$table->timestamp('scheduled_arrived_at');
Törlésük a down() metódusban:
$table->dropColumn(['scheduled_departured_at', 'scheduled_arrived_at']);
Utána futtassuk is az adatbázis migrálást, hogy bekerüljenek az új mezők a flights táblánkba: php artisan migrate
A
Flight Model osztályban adjuk is hozzá ezt a két mezőt a $fillable
változóhoz újabb tömbelemként, hogy majd sikeresen tudjuk az adatbázisba
betölteni az értékeket.
Nálam a FlightsController-ből még
hiányoznak a create, store (és az edit, update metódusok is, de
azokat későbbre hagyom + gyakorlásként a destroy-t is meg lehet csinálni majd), úgyhogy ezeket most létre is hozom:
public function create()
{
return view('flights.create', [
'captains' => Captain::orderBy('name')->get(),
'airlines' => Airline::orderBy('name')->get()
]);
}
public function store(Request $request)
{
Flight::create(request()->all());
return redirect(route('flights.index'));
}
Viszont az
ezekhez köthető útvonalaink még hiányoznak a web.php-ból. Én az eddigi
flights-hoz köthető útvonalakat kikommenteltem (törölhetjük is), és
helyette ezt használom, mert egyszerűbb és rövidebb is:
Route::resource('flights', App\Http\Controllers\FlightsController::class);
Ezzel ugye mind a 7 RESTful útvonalat létrehozom a repülőjáratokhoz, az útvonal nevekkel (name) együtt.
Adjuk
hozzá a létrehozó és szerkesztő weblinkeket a flights / index nézethez.
A két linket helyezzük el logikusan (az elsőt a nézet címe alatt, a
másodikat a repülőjáratok felsorolásába):


Ezután
térjünk rá a létrehozó nézetre, hiszen, ha azt létrehozzuk és
megfelelően implementáljuk, akkor utána a szerkesztési nézetet már
könnyebb lesz másolni és pluszban egy kicsit még paraméterezni a
megfelelő működéshez. Itt már mindent úgy állítok be, hogy a validációs
szabályokat összehangolom az adatbázistábla megszorításaival és az
általunk elvárt működéssel is.

Jó
sok mező van most már benne, itt én most csak a form-ot magát emeltem
ki képként (de figyeljünk, hogy lett id-ja a form-nak!). Tipp: Jó szokásom szerint, aki szeretné felhasználni a kódot, az a bejegyzés végén
lévő Github commit részeként megtekintheti az érintett fájlokat és a teljes
tartalmukat.
Dátumkiválasztók a böngészőkben
Amire a kódban külön fel szeretném hívni a figyelmet,
hogy egy új bemeneti típust használtam, a datetime-local-t, ami egy
nagyon hasznos elem. Segítségével együttesen tudunk dátumot és időt
meghatározni. Van vele viszont "probléma" is sajnos, ami pedig a
böngészők és nyelvi beállításaik különbségéből adódhat. Míg Chrome-ot
(balra) én magyarul használom, emiatt a "magyar szemek" számára
megfelelően jelenik meg, a Firefox-ot angolul használom, emiatt a
Firefox-ban (jobbra) az angolszász dátum- (hónap/nap/év) és 12 órás
időformátumot (AM/PM) követi.

Ha viszont a Firefox-hoz telepítem a magyar nyelvi csomagot
és a beállításainál átállítom a nyelvet magyarra, majd újratöltöm a
weboldalamat, akkor már a magyar dátum- és időformátumban fog megjelenni
ez a bemeneti mező:

Látható
tehát, hogy ennek a mezőnek a megjelenítése a böngészőnk nyelvi
beállításától függ. Fontos viszont, hogy adatbázis szempontból (tábla beszúrásnál) működik
mindkét formátummal, úgyhogy ott nincsen probléma (megy magyar nyelvű Chrome-ban és angol nyelvű
Firefox-ban is az új repülőjárat felvétele).
Validációs
szempontból, látható, hogy a HTML input mezőhöz már adtam hozzá
megszorításokat (lásd a fenti HTML kódot), így a dátumos mezőkbe bekerültek,
minimális és maximális értékek a dátumhoz, ezek a korábbi / későbbi
dátumok a lenyíló dátum kiválasztásánál szürkék, inaktívak, így a
felhasználó nem is tudja őket kiválasztani. Ezek azonban statikus
értékek, tehát olyat például nem tudok nekik beállítani, hogy a
minimálisan kiválasztható dátum a mai nap legyen, vagy hogy a
repülőjáratnál a megérkezés ideje mezőnél a minimálisan kiválasztható
dátum az elindulás ideje legyen (erre persze 0% lenne még az esély,
kivétel, ha fénysebességgel menne a repülő).
Dátumszűrés: Just Validate Plugin Date
Az imént felsorolt
validációs beállításokhoz valamilyen további ellenőrzésre lenne szükségünk,
amihez a HTML kevés, viszont a Javascript és a kiválasztott
osztálykönyvtárunk már tud segítséget nyújtani, illetve annak egy
plugin-ja (kiterjesztése). A telepítést ismét megpróbáltam CDN-en keresztül, de sajnos 404-es hibába futottam:

A
böngészőben is jelzi, hogy nem található ez a verziójú plugin (a
"3.8.1" helyett a "latest" szót írtam be természetesen, de automatikusan
ugrott erre a verziószámra és jelezte is, hogy nem működik). Úgyhogy
váltanom kellett és inkább az npm-es telepítést választottam ennél a
plugin-ná l(mivel ez a fő csomagnak csak egy kiterjesztése), emiatt inkább a fő csomagot, a Just Validate-et is npm
segítségével telepítettem, majd importáltam be az alkalmazásomba.
Just Validate telepítése
A terminal-ban így telepítettem:
npm install just-validate
Ennek
hatására bekerül a csomag a node_modules mappába (ellenőrizhetjük és
böngészhetjük is a tartalmát) és most már a Javascript kódjainkban is használható lesz,
hasonló módon, mint ahogy a SCSS fájloknál megismertük itt. De ehhez a resources/js/app.js fájlt bővítsük ezzel a sorral:
window.JustValidate = require('just-validate');
Majd következhet a terminal-ban az npm run dev parancs kiadása, amivel "belefordítódik" ez az importálás a public/js/app.js fájlba. Ez azért is történik meg, hiszen a projektünk gyökerében lévő webpack.mix.js fájlban alapértelmezetten benne volt ennek az app.js fájlnak a fordítása a forrással és a céllal együtt.
Ez
azonban még nem elég, hiszen ezt az app.js fájlt még el kell helyezni
a használat miatt az "alnézet" oldalunk HTML kódjában is: most ugye mi a nézetek közül a
flights/create.blade.php -t fejlesztjük, úgyhogy töltsük ki vele ezt a
"szekciót":
@push('head-scripts')
<script src="{!! mix('js/app.js') !!}"></script>
@endpush
Oké, most már használható lenne a Just Validate
csomag a flights/create nézetben, azonban ez nekünk még mindig nem elég,
hiszen mi egy plugin-ját akarjuk használni, amivel a dátumokat tudjuk ellenőrizni.
Just Validate Plugin Date telepítése
Telepítsük ezt is a projektünkbe a
terminal-on keresztül:
npm install just-validate-plugin-date
Ezután a resources/js/app.js fájlt bővítsük ezekkel a sorokkal:
import JustValidatePluginDate from 'just-validate-plugin-date';
window.JustValidatePluginDate = JustValidatePluginDate;
Majd következhet a terminal-ban az npm run dev
parancs kiadása (megjegyzés: ha tudjuk előre, hogy sokszor / többször
kell majd fordítanunk ezeket a kijelölt fájlokat, akkor az npm run watch
parancsot is alkalmazhatjuk, ilyenkor ő figyeli a webpack.mix.js-ben kijelölt fájlokat, és
ha mi mentjük őket, akkor automatikusan és gyorsan elvégzi az
újrafordításukat). Így importáltuk ezt a plugin-t is az app.js fájlba.
Jöhet ismét a flights/create nézet fájl, és a scripts részt fogjuk
bővíteni (ami gyakorlatilag a body záró tag-je elé fog bekerülni a végső
kódban):
@push('scripts')
<script>
const validation = new JustValidate('#flightCreateForm');
validation.addField('#scheduled_arrived_at', [{
plugin: JustValidatePluginDate(() => ({
isAfter: document.getElementById('scheduled_departured_at').value
})),
errorMessage: 'A tervezett érkezési dátumnak/időnek a tervezett indulási dátum/idő után kell lennie.',
}])
.onSuccess((ev) => {
ev.target.submit();
});
</script>
@endpush
Ezzel beállítjuk, hogy a tervezett érkezési
dátumnak és időnek a tervezett indulási dátum és idő után kell lennie,
ahogy a hibaüzenet - errorMessage - is jelzi a kódban, hogy ha nem
teljesül ez a feltétel. Az isAfter-en kívül a következő szabályokat
tudjuk még beállítani vele:
- isBefore (valamilyen dátum előtt)
- isBeforeOrEqual (valamilyen dátum előtt vagy megegyezően)
- isAfterOrEqual (valamilyen dátum után vagy megegyezően)
- isEqual (valamilyen dátummal megegyezően)
- format (valamilyen specifikus dátumformátumot is meg tudunk neki határozni)
Ezek
együttesen is alkalmazhatók, nyilván logikusan adjuk meg a
dátumhatárokat (például ne legyen a minimális dátumlimit nagyobb, mint a
maximális dátumlimit) és figyeljünk a beszédes hibaüzenetekre is. A kódban én benne is hagytam két ilyen validációs
beállítást példaként, kikommentelve (format, isBefore).
Tesztelés
Teszteléskor meg is kapjuk a hibaüzenetet a Mentés gomb alatt, ha nem megfelelő a két dátum viszonya (sárgával kiemeltem a fontos részeket):

Repülőjáratok szerkesztése és frissítése
Innentől ez már nem is lenne nehéz, ugye? De azért segítek. A Laravel-es háttér kapcsán vegyük át a teendőket:
- Adattábla: ez már teljes ✅
- Útvonalak (edit, update): ezek megvannak ✅
- FlightsController
megvan ✅, de hiányoznak belőle még az edit és update metódusok ❌ (a
felsorolás után ezzel fogom folytatni rögtön)
- Index nézetből el tudunk jutni a szerkesztési űrlapra ✅
- Az edit nézetünk hiányzik ❌, de ahhoz fel tudjuk használni a create nézetet, csak kicsit kell átalakítani ✅
A FlightsController új metódusai:
public function edit(Flight $flight)
{
return view('flights.edit', [
'flight' => $flight,
'captains' => Captain::orderBy('name')->get(),
'airlines' => Airline::orderBy('name')->get()
]);
}
public function update(Request $request, Flight $flight)
{
$flight->update(request()->all());
return redirect(route('flights.index'));
}
A flights/edit nézet:

Mi változott a create űrlaphoz képest az edit-ben?
- A form action attribútuma az update útvonalra küldi majd el az adatokat.
- A form id attribútuma flightEditForm lett.
- A @csrf direktíva után bekerült a @method('PUT') direktíva, ahogy ezeket már tanultuk itt.
- Az
egyszerűbb input mezőknél a value attribútum kap előre beállított
értékeket. Amelyik mező nem kötelező az adatbázisban történő értékadás (lehetnek NULL-ok is), ott egy @if
direktívát használva ellenőrzöm, hogy volt-e értéke a táblában.
- A select-option-öknél a @selected direktívát használtam arra, hogy az adatbázisban lévő értéket állítsam be alapértelmezettnek.
- A gomb feliratát pedig "Mentés"-ről "Frissítés"-re írtam át.
- és ennyi...
A
két @push szekcióban annyi a különbsége a create nézetben
meghatározotthoz képest, hogy most a new JustValidate konstruktor
paramétere már az új #flightEditForm lesz és a validáció ugyanúgy fog
működni, mint a create esetében.
Összegzés
További
információkhoz érdemes részletesen áttekinteni a Just Validate csomag dokumentációját, példákat (ha valaminek a működése nem világos, akkor az űrlap és a kapcsolódó Javascript kódját is lehet böngészgetni, hiszen kliens oldalon vagyunk). Ki is lehet próbálni azokat a funkcionalitásokat, amire még szükségetek van.
Gyakorlásként tehát megnézhetitek és
tesztelgethetik még a Just Validate és dátumellenőrzés plugin-jának
funkcionalitásait is.
A bejegyzés kódjait ebben a Github commit-ben találjátok meg.
Összefoglalásként
azt gondolom, hogy rengeteget tanulhatunk ebből a bejegyzésből is,
főleg annak kapcsán, hogy hogyan kell egy telepített Javascript csomagot
működésre bírni és használni.
Ez meglehetősen hosszú bejegyzés
lett, sokat is küzdöttem némelyik probléma megoldásával, így másik
kliens oldali Javascript validációs osztálykönyvtárat már nem ismertetek külön, viszont a funkcionalitások a többinél is hasonlóak vagy csak kicsit eltérőek. A következőkben már a Laravel-es, tehát a szerver oldali validációval fogom folytatni.