Harmadik generációs formok

formA formok azok az eszközök amelyeken keresztül a user a legszabadabban tud webalkalmazásunkkal kommunikálni. Alapesetben a formok nem túl intelligensek, de egy kis munkával igen kifinomult eszközökké változtathatjuk őket.

Első generációs formok

Első generációsnak nevezem azokat a dinoszauruszokat amelyek a kliens oldalon nem tesznek mást, csak a user kezébe adják a szabványos form elemeket a maguk pőreségében. Ez azt jelenti, hogy nem használnak semmilyen JavaScriptet a bevitt adatok értékelésére, validálására vagy ellenőrzésére, hanem egyszerűen amit a user bevitt azt egy submit gomb segítségével úgy ahogy van elküldik a megcélzott szervernek.

Az első generációs egyedekkel az a baj, hogy ha a user nem tölt ki egy kötelező mezőt, vagy nem helyes vagy elvárt értéket ad egy elemnek, akkor ez csak egy kliens-szerver kommunikáció után derül ki, a szerver (jó esetben) hibaüzenetekkel szórakoztatja a usert, aki kezdheti előről az adatbevitelt. Röviden szólva kényelmetlen, lassú és nehézkes.

Az első generáció általában azt is jelenti, hogy a form egyáltalán nincs semmiféle CSS-sel megfűszerezve, így a jellemzők közé nyugodtan felvehetjük a “ronda” tulajdonságot is.

Egyetlen előnyük, hogy 100%-ig biztosított a működésük, nem zavarja őket a kikapcsolt JavaScript, vagy egy nem átlagos user agent.

Második generációs formok

Az első generáció hátulütőit első körben pár intelligens programozó úgy kerülte ki, hogy a submit gomb megnyomása lefutatta a validálást, ellenőrzést a kliens oldalon mindenre amire kellett. Ha talált hibá(ka)t pár karácsonyfának álcázott hibaüzenettel aggadta tele a formot amiből a user megtudhatta, hogy miféle bűnöket követett el. Ha nem volt már hiba, akkor a submit ténylegesen elküldte a szervernek a formot, ami ezután már nyugodtan feldolgozhatta a kapott adatokat.

Zárójelben megjegyzem, még itt az elején mielőtt valaki félreértené, hogy miről is van itt szó, hogy a szerver oldalon MINDIG ellenőrizni KELL a bejövő adatokat, függetlenül attól, hogy a kliens oldalt mennyire tettük intelligensé. Hogy miért? Mert semmi sem biztosítja, hogy a szerver az általunk kreált klienstől kapja az adatokat.

Ennél a generációnál, hogy a süsü usert informálja arról, hogy mit szeretnénk tőle kis piros csillagocskákat tett az okos programozó agy a kötelezően kitöltendő mezők mellé. A userek azonban általában nem úgy cselekednek ahogy azt mi a programozók elvárják tőlük. Szóval sokszor ezek a formok 4-5 submit kísérletet is el kellett szenvedniük mire végre a user mindent kitöltött amit kell és mindent úgy ahogy akartuk. Hát így néz ki egy tenyeres-talpas programozói megoldás a user problémáira.

A második generáció már kapott egy kis CSS fűszert is, kulturáltabb kinézetet adva a formnak.

A második generáció már kényelmesebb és sokkal kevésbé nehézkes, elkerüli a felesleges kliens-szerver kommunikációt, de sokszor még mindig lassú és bosszantó. Ennél a generációnál már külön figyelmet kell szentelni annak, hogy kikapcsolt JavaScript melett is működőképes maradjon a form, persze ebben az esetben a kliens oldali funkciók nélkül.

Harmadik generációs formok

Harmadik generációsnak nevezem azokat a megoldásokat, amelyek a user kezébe intelligens és könnyen használható bizgentyűket adnak. Általában a plusz funkciók tekintetében erősen támaszkodnak a JavaScript és a CSS használatára, ezek nélkül pedig sima első generációs dinoszauruszokká vállnak.

Legismertebb egyedük az autocomplete mezők. Gondolom már mindenki látott ilyet, azaz olyan input mezőt amibe ha elkezdünk beleírni akkor maga alá nyit egy kis dobozkát a lehetséges értékekkel. Legismertebb alanya a google suggest. Az autocomplete mezők a más programozási környezetekben alapból rendelkezésre álló comboboxokat utánozzák, ami a html nyelvben elvileg az input és a select szerelmének gyümölcse lenne. Mivel az elmúlt 10 évben nem volt érdemi változás a html szabványban a combobox sem került bele a webfejlesztők eszköztárába.

Sajnos azt látom, hoyg a webfejlesztők többsége megelégszik ezzel és beletörődik, hogy a formjaink olyanok mint a pincsikutyák: rondák és buták. Ennek azonban nem kellene így lennie, hiszen egy-egy kicsi JavaScript alkalmazásával könnyen evolúciós ugrásra késztethetjük formjainkat.

A következőkben szereplő kódokat sokkal inkább gondolatébresztőnek szánom mint valamiféle tutorialnak. Ennek örömére nem is tesztelem le a bemutatott megoldásokat csak Firefox alatt, így más böngészőkkel vagy IE-vel nem biztos, hogy teljesen működőképesek.

Beviteli maszkok

Amit a formok esetében a magam részéről a legrusnyábbnak tartok, az az amikor a bekért adatok formátumát úgy próbáljuk biztosítani, hogy a usert rákényszerítjük valami összetákolt bizgentyű használatára. Általános példa, hogy a hitelkártya számot így kérik be:

Négy input mező, a user meg hagy egerezzen vagy tabozzon közöttük. Ha felruháznák egy inputot azzal a tulajdonsággal, hogy csak bizonyos formátumú inputot fogadjon el, akkor nem kell csak egyetlen input.

Mondjuk ha egy összeget szeretnénk bekérni, akkor ugye azt várjuk, hogy csak számokat írjon be a user. Pirike persze ártatlan inputunkba ügyesen begépeli, hogy “25 ezer”. Ahelyett, hogy hibaüzeneteket lődöznénk Pirikére megtehetjük, hogy az inputunkat megtanítjuk arra, hogy csak számokat fogadjon el. Ennyi az egész:

Event.observe($('csakszam'), 'input', csakszamKezelo);
csakszamKezelo = function(){
  var csakszam = $('csakszam');
  csakszam.value = csakszam.value.replace(/\D/g, '');
  }//csakszamKezelo

Nem teszünk mást mint az input esemény bekövetkezésekor a bevitt értékből kiszedünk minden nem szám karaktert. Az eredmény itt kipróbálható:

A legtöbb Pirike rá fog jönni, hogy nincs más választása mint a 0-k nyomkodása, mert az “ezer” sehogy sem íródik bele a mezőbe akármilyen erővel is kalapálja be.

Ha szeretnénk az input mezőnk IQ-ját még pár ponttal növelni és ezzel a maradék Pirikék kedvébe is járni, akkor azt is megtehetjük, hogy ha a user megnyom egy “e” betűt, akkor a meglévő szám végére hozzáíródjon 3 darab 0.

A függvényünket csak kicsit kell módosítanunk.

csakszamKezelo = function(){
  var csakszam = $('csakszam');
  csakszam.value = csakszam.value.replace(/e/, '000');
  csakszam.value = csakszam.value.replace(/\D/g, '');
  }//csakszamKezelo

Az okosabb input így néz ki:

Ha a user a mezőbe beír egy “e” betűt, akkor 3 nulla íródik ki helyette.

Így már egész kényelmes bevinni akár nagy számokat is, azonban hacsak nem állunk szerződésben egy szemüveggyártóval, akkor észre fogjuk venni, hogy a beírt 200000 (200.000) és 2000000 (2.000.000) csak hosszas szemgúvasztás után különböztethető meg. Ha továbbra is szereténk a felhasználók elégedettségi szintjét növelni, akkor szúrjunk be gépelés közben automatikusan helyiérték elválasztókat.

Ez a probléma már némiképpen összetetteb mint az előzőek, de még ezzel is megbírkózik egy nyúlfarknyi JavaScript kódocska.

iMaszk = function(mezo){
//a maszk paraméterben érkező beviteli maszkot automatikusan hozzáadja a begépelt szöveghez és nem engedi felülírni
  this.mezo = mezo;
  this.reverse = false;  //hátulról illesztjük a maszkot vagy előről
  this.maszk = '### ### ### ###';
  Event.observe(mezo, 'input', this.osszegEgesz.changer.bindAsEventListener(this));
  //adjunk értéket az input mező maxlength tulajdonsaganak
  mezo.maxLength = this.maszk.length;
  //a fixkarakter tömbben vannak azok az indexek ahol a fix karakter szerepel a maszkban
  this.fixkarakter = new Array();
  for(var i=0;i<this.maszk.length;i++) if(this.maszk.charAt(i) != '#') this.fixkarakter.push(i);
  }//iMaszk

iMaszk.prototype.osszegEgesz = {}

iMaszk.prototype.osszegEgesz.changer = function(){
  //amikor változtatjuk a bevitt értéket akkor frissíteni kell az input mező tartalmát
  var maszkoltErtek = '';
  var pos = 0;
  //gyorsbillenytűk átalakítás, és a többi nem szám karakter kiszűrése
  this.mezo.value.toArray().each(function(karakter){
    switch(karakter){
      case 's':
        maszkoltErtek += '00';
        break;
      case 'e':
        maszkoltErtek += '000';
        break;
      case 'm':
        maszkoltErtek += '000000';
        break;
      }
    if(karakter.search(/\D/) == -1)
      maszkoltErtek += karakter.replace(/\D/, '');
    });
  var o = this;
  //a megszűrt ertek stringbe beszúrjuk a maszk elválasztókat
  this.fixkarakter.each(function(i, index){
    if(i < maszkoltErtek.length){
      pos = maszkoltErtek.length-i;
      maszkoltErtek = maszkoltErtek.substr(0,pos) + o.maszk[i] + maszkoltErtek.substr(pos,maszkoltErtek.length);
      }
    });
  this.mezo.value = maszkoltErtek;
  }//osszegEgesz.changer

A helyiértékeket megjelenítő input így néz ki:

A fenti kóddal a következő tulajdonságokkal ruháztuk fel az inputot:

  • Ha a user a mezőbe beír egy “s” betűt, akkor az input mezőbe 2 darab 0 íródik be.
  • Ha a user beír egy “e” betűt, akkor 3 darab 0.
  • Ha egy “m” betűt akkor 6 darab 0 íródik be.
  • Ha bármi más nem szám karaktert ír be, akkor az eldobásra kerül, és nem íródik be.
  • A könyebb olvashatóság érdekében a beírt szám ezresenként automatikusan tagolódni fog.

Persze ezzel a módszerrel maszkolhatjuk inputjainkat tetszés szerint bármire, telefonszám formára, tajszám formára, angol ABC kis és nagybetűire, vagy bármi másra. A maszkolt inputokkal kényelmesebb adatbevitelt érhetünk el, és ha jól eltaláljuk akkor a felhasználóink is szívesen fogják használni kiokosított adatbevieli mezőinket.

Önátalakítók

Egy másik gyakran használt és otrombán megvalósított bizgentyű a dátumokhoz kapcsolódik. Mindenki ismeri, hogy milyen macerás egy háromszoros selectből kiválasztani a születési dátumot. Egy select az éveknek 1222-től 2017-ig, egy a hónapoknak és egy a napoknak. Ha ilyesmit látok, akkor a magam részéről február 30-át választom ki bosszúból, amiért ennyit kellett nyösztetnem az egyébként is agyongyötört egérkémet, nem beszélve arról, hogy hány byte-ot kellett feleslegesen letöltenem. Egy harmadik generációs dátum mezőt egyetlen inputként is meg lehet valósítani.

Elvárásunkat az inputtal kapcsolatban az alábbi lista mutatja.

  • Ha a user beír egy számot mondjuk egy 5-öst, akkor az az aktuális év aktuális hónapjának 5-ikéjét jelentse, azaz most a cikk írásakor 2008.02.05-t
  • Ha a user egy plusz jelet és egy számot ír be (pl +4), akkor az jelentsen egy 4 nap múlvát, azaz ha ma 2008.02.11 van, akkor a +4 2008.02.15-t jelent.
  • Ha a user két számot ír be kötőjellel elválasztva pl 5-2, akkor az jelentse az aktuális év 5. hónapjának 2. napját.
  • Ha a user három számot ír be kötőjelekkel elválasztva, akkor az jelentsen egy év-hó-nap formátumot, pl 4-7-25 Jelentsen 2004.07.25-ét.
  • Amint a fenti példákból is látható a vezető nullák legyenek elhagyhatóak, azaz 1-5, 01-5 és 01-05 legyenek egyenértékűek.
  • Ezen felül pedig mivel nem szeretnénk, hogy a user beírja, hogy “február”, vagy “gumicumi” csak azokat a karaktereket engedélyezzük amelyek feltétlenül kellenek, azaz a számokat a + és a - jelet.
  • Azt is szeretnénk, hogy a február 30 féle dátumok automatikusan átkonvertálódjanak, a teljesen dilettáns számkombinációk (pl 17-45) pedig a mai nappá alakuljanak.

A JavaScript kódunk lényegében arról gondoskodik, hogy az inputunk elveszti a focust, akkor egy értelmes adat maradjon benne. Fogjuk az előző objektumot és gyúrjuk át direkt erre a feladatra, persze csak a könnyebb szemléltetés kedvéért

dMaszk = function(mezo){
//a maszk paraméterben érkező beviteli maszkot automatikusan hozzáadja a begépelt szöveghez és nem engedi felülírni
  this.mezo = mezo;
  this.reverse = false;  //hátulról illesztjük a maszkot vagy előről
  this.maszk = '####-##-##';
  Event.observe(mezo, 'input', this.datum.changer.bindAsEventListener(this));
  Event.observe(mezo, 'blur', this.datum.changeAfterBlur.bindAsEventListener(this));
  //adjunk értéket az input mező maxlength tulajdonsaganak
  mezo.maxLength = this.maszk.length;
  //a fixkarakter tömbben vannak azok az indexek ahol a fix karakter szerepel a maszkban
  this.fixkarakter = new Array();
  for(var i=0;i

Ez a JavaScript kód már kicsit vastagabb volt, de azt hiszem bizonyos esetekben megéri a fáradtságot.

Fő a kényelem

Ide sorolhatóak azok a megoldások, amelyek valamelyest a user keze alá dolgoznak. Ilyen például az, hogy a focust a form megjelenésekor az első szerkeszthető mezőre hozzuk. Pontosan erre szolgál a prototype form.focusFirstElement() függvénye.

Submit babrálók

Ezek a megoldások arra hivatottak, hogy a form ne küldődjön el amíg nem gondoljuk úgy, hogy már elküldhető, vagyis mondjuk minden kötelezően kitöltendő mező ki van töltve valami jónak tűnő adattal. Ez megoldható mondjuk úgy, hogy a submit gomb disabled állapotban van és csak akkor váltódik enabled-re amikor a kívánt inputok már ki vannak töltve valid adatokkal.

Ide sorolhatók az enter-t tab-ra váltó konverterek, amellyek arra szolgálnak, hogy ha a user egy input mezőben üt egy entert, akkor a form submit eseménye ne következzen be, hanem a focus egyszerűen csak ugorjon a következő mezőre.

In place editorok

Azt hiszem ez a harmadik generációs form bizgentyűk másik nagyon elterjedt csoportja. Ezek egy-egy textarea mezőt alakítanak mini szövegszerkesztővé. Több megoldásuk is van (TinyMCE, FCKeditor, stb) amit beépíthetünk projectjeinkbe ha éppen a szükség úgy hozza. Ezek a megoldások általában már cseppet sem nyúlfarknyiak.

A tanulság

A tanulság a fentiekből az, hogy ne ragadjunk le annál, hogy a weben mivel mit szokás, és mit hogyan szokás. Itt a web2 (már jóideje) ami egyrészt arról szól, hogy rugdaljuk fel a régi szokásokat. A web a leggyorsabban változó médium, ami az elmúlt 10 évben nem igazán adott új technikai eszközöket a kezünkbe. Ez a rossz hír. A jó meg az, hogy a jól ismert html bizgentyűinket kifordíthatjuk a bőrükből és új tulajdonságokkal ruházhatjuk fel őket a user örömére. Mert ha már webet gyártunk akkor azt ne magunknak tegyük.

Illetve mégse...

Még egyszer szeretném kihangsúlyozni, hogy ha a kliens oldalon bármilyen varázslatot is eszközöltünk a szerver oldalon továbbra is mindent ellenőriznünk kell. Másrészről pedig az itt bemutatott ötletek nem feltétlenül alkalmazhatók vagy alkalmazandók minden esetben. Ha például az alkalmazásunkban naponta 40-szer kell dátumot beírni, akkor jól jön ha egy 5-öst nyomva meg tudom adni, hogy 2008.02.05. Ha egy egyszerű weblapunk van ahol a user nyolc évenként egyszer ad meg egy dátumot, akkor lehet, hogy az új bizgentyűk megértése több időt vesz igénybe nála, mintha csak kirakjuk a három selectet a szokásos módon. Szóval ne feldekezzünk el a megismerhetőségről sem. De ez már egy másik történet lesz...


18 thoughts on “Harmadik generációs formok

  1. Praktikus a “harmadik generációs” űrlapokról szóló fejezeted, de az elnevezések szerintem nem találóak. A CSS okos használata nem függ össze a formok intelligens kialakításával; nagyon rossz formot is lehet elegáns megjelenéssel összedobni, és fordítva. Egy pontot hiányoltam az összefoglalásodból, mégpedig a maxlength attributum szinte kötelező érvényű használatát. Noha JavaScriptből te is megadtad, de igen kevés az a helyzet, amikor nem adható meg előre a várt adat max hossza – HTML leírás szintjén.

    A generációkra osztás kapcsán ha a CSS-t említetted, akkor érdemes a table layout-tal kialakított formokról is szólni, amelyek kitöltése külön művészet, ha a vizuálisan egymást követő mezők HTML szinten nem soron következők.

    Érdemes még megemlíteni a “negyedik generációs” formokat, amelyek azzal kívánnak kitűnni a többi közül, hogy speciális automatizmusukkal segítik a látogatót. Ilyen például az OTP login doboza, ahol a weboldal a maximum karakterszámot elérve helyetted nyom tabot, és ha még te is rányomsz egyet megszokásból, az a nap fénypontja.

  2. Szerintem pirike sose fog “+12” -ket beírni, ezzel ellentétben biztosan örülne 3db text mezőnek egymás mellett, amik szélessége sejteti az év, hónap, nap sorrendet, és megfelelő számú karakter begépelése után átugrik a fókusz a következő inputra.

    Esetleg az input háttérszínével jelzi, ha nem stimmel valami az illető boxban…

  3. Ez a +4 dolog szerintem is eléggé hajánál-fogva-előráncigált dolog. Ha egy ilyet meg akarsz értetni a felhasználóval, sokkal több bájtnyi szöveget kell leírnod magyarázatként, mint ahányat megspóroltál azzal, hogy három szelect helyett egy text-ed van.
    Az “s” betűre beíródó két nullát hasonlónak érzem, én még sose láttam, hogy valaki a 200-at 2száz-nak akarta volna megadni.
    Persze ettől függetlenül jó az írás, és ahogy írtad is, nem tutorial, csak gondolatébresztő. Annak jó.

  4. Gyulus: Most gyártok egy böngészőben futó platformfüggetlen személyes feladat kezelő alkalmazást. Amikor a határidőket kell megadni egy feladathoz ott pl elé kézenfekvő az 5 nap múlva típusúaknál.

    Dolgozok egy könyvelőprogramon is, ott meg jól jönnek a számok bevitelét gyorsító eljárások. Szóval minden attól függ, hogy milyen igényt szolgál ki a program. Végül is erre akartam kilyukadni, hogy a felhasználói igényeket szolgáljuk ki, ne a technikaiakat.

  5. Két fölöttébb hasznos észrevételt szeretnék tenni az egyébként kellemes és hasznos cikkel kapcsolatban.

    Nem ajánlom a form.focusFirstElement()-féle megoldást, tehát amikor az oldal betöltődésekor automatikusan fókuszt kap a form első eleme. Egyrészt elgörgetheti az ablakot, másrészt pedig nem teszi lehetővé, hogy a billentyűzet nyilaival görgessem az oldalt. Helyette inkább a tabindex és az accesskey attribútumok használatát javaslom, mert így a tab megnyomásával máris form(á)ba kerülhetek.

    > “Ez megoldható mondjuk úgy, hogy a submit gomb disabled állapotban van és csak akkor váltódik enabled-re amikor a kívánt inputok már ki vannak töltve valid adatokkal.”
    Csak óvatosan, nehogy a JavaScript nélküli emberkék nyomkodnivaló nélkül maradjanak! Biztonságosabb, ha a submit gombot JS-ből deaktiváljuk, onloadra, vagy DomContentLoaded eseményre.

    Gargalizálj és légy bulldog! 🙂

  6. Karan: Igazad lehet ha egyáltalán kell görgetni az oldalt. Ez megint attól függ, hogy mivel is dolgozunk.

    A submitot meg persze én is Js-ből állítom disabledre ha kell:)

  7. Ha csak gondolatébresztő, akkor nem kellenek a kódrészletek sem. Ha meg kicsit több, mint gondolatébresztő, akkor nem csak FF alatt kéne működnie. IE7 alatt az egész oldalad szétesik (illetve inkább össze-vissza esik), a cikkbéli példákból pedig nem működik egy sem.

    Szóval szerintem inkább az a gondolatébresztő, hogy valaki így akar szakmai jellegű cikket írni. Komolytalan és igénytelen.

  8. A dátumoshoz egy észrevétel: amikor xx-x-x alakban írja be a dátumot akkor ne 20xx-x-x -re alakítsa át, hanem 19xx.
    Pl. 57-6-4 -> 1957.06.04
    Ez főleg születési idő megadásánál hasznos.

    Egyébként nem értek egyet Dr.NO-val. Ez a bejegyzés is – akár csak a többi – sok jó és hasznos információval szolgált nekem. Szerintem ezzel nem vagyok egyedül…

  9. Dr.No: Nekem szoktak segíteni a kódrészletek bizonyos dolgok megértésében, még akkor is ha nem 100%-ig azt mutatják be ami nekem kell. Szerintem vannak mások is akik így vannak ezzel.

    Az IE-t meg világ életemben utáltam. Ha nem muszáj, akkor nem foglalkozok a nyűgjeivel. Ha fejlesztek valamit általános felhasználásra, akkor figyelek, hogy használható legyen IE6, IE7 alatt. De se a bolg se ez a cikk nem arról szól, hogy hogyan éljenek az egyébként életképes dolgok IE alatt.

  10. Gouranga kedves rrd!

    Azt a hítszázát, de nagyon benne vagytok ti ebben… 🙂
    Egy szót sem értettem az egészből, de nagyon tanulságos volt olvasni… ;D
    Igazából azért írok, most ide, mert nem találtam meg a mailos elérhetőséged, de igencsak tetszik az az 1%-os flash ott a balfelső sarokban és betenném az oldalamra, csak nem tudom hogyan kell leszedni onnét, úgyhogy azt szeretném kérni, küld már el a kódját, vagy mittudom én, hogy an működik… 🙂
    (Amúgy most tláltam meg az oldalad asszem és be is linkolnálak, hozzám ha nem gond, hátha találok majd még egy két okosságot itten…)
    Előre is köszi!

    Hare Hare

  11. Gouranga!

    Ha a cikk célja a gondolatébresztés volt, akkor ezt a célt messzemenően elérte, úgy látom sok gondolat ébredt. Vagy egyszerűen csak egyre többen olvassák az írásaidat? Akár így van, akár úgy, mindkettő jó dolog 🙂

  12. Sok időmet megkímélted volna, ha a kódokat helyesen írod. Pl. a csakszam.value.replace(/\\D/g, ”)-ben nem teszel 2 backslasht a D elé.
    Talán Dr.NO is erre gondolhatott egy éve.

  13. az input maszkos dolgoknak egyetlen hátulütője ha mondjuk számlaszámot adok meg mint felhasználó, és elsőre azt hiszem hogy a bank azonosítóját (első három számjegy) nem kell megadnom, majd gépelés közben rájövök, visszamegyek a balra gombbal, begépelem az első számjegyet… és mehetek 6-ot balra, meg megint. értsd: elrontja a kurzor pozícióját 🙁

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöljük.