fbpx
A hibátlan kód meséje ShiwaForce Admin 2015. április 28

A hibátlan kód meséje

Vegyünk egy konkrét példát:

Az adott oldalra ellátogató felhasználónak a felületen meg kell jeleníteni két gombot. Az előzetesen átküldött dizájnon látható “Elfogadom” megnyomásával elfogadjuk a feltételeket, míg  az “Elutasítom” pedig elutasitjuk. Az “Elutasítom” gomb megnyomására jelenítsünk meg egy megerősítő layer-t, hogy biztosan elutasítja a Felhasználási feltételeket.

Korábban, egészen más stílusban programoztunk: úgy készítettünk kódokat hogy if-el kezdtük. Ugye mindenki emlékszik még? 😉

if(document.all){
  element.attachEvent(‘onclick’,showLayer);
}else{
  element.addEventListener(‘click’,showLayer);
}

A tapasztaltabbak viszont azonnal kiszúrják, hogy nem feature ellenőrzés van a feltételben. (akkoriban még nem az volt a divat). Alakítsuk hát át a kódunkat. Ugyan még messze vagyunk a megoldástól, már most hibás a kód. Gondoljunk csak az ie11 újításaira, ahol is kivették a document.all- funkciót.

Tehát az új mintakódunk:

if(element.addEventListener){
  element.addEventListener(‘click’,showLayer);
}else{
  element.attachEvent(‘onclick’,showLayer);
}

Meg is volnánk, ráadásul egészen crossbrowser lett a megoldásunk, valójában ie5-től már működik, de nézzük csak tovább felület oldalról hogy hogyan is kellene működnie: van két gomb, azaz két eseménykezelő, a felugró layeren is van két gomb amivel meg lehet erősíteni a szándékot, az még két eseménykezelő. Lehet, hogy a layerre kell egy bezár gomb is, az még egy eseménykezelő. A layer mellé kattintást is jó lenne lekezelni, akkor még egy. Gyakorlatilag ha crossbrowserek akarunk maradni, akkor az if-ek a kódunkban úgy elszaporodnak, mint a nyulak. 🙂

Alapvetően a hibák gyakoriságát boncolgatjuk így ismét ott tartunk, hogy sok kódban sok a hibalehetőség, szóval ez nem a legjobb út. Gyorsan térjünk is le róla, vannak erre megfelelő libek, például a méltán népszerű jQuery. Ezzel a kódunk is egyszerűsödik:

$(element).click(showLayer);

Így egy-egy sor lett minden kattintás felfűzése. Nem véletlenül az egyik legnépszerűbb lib a jQuery. Némi fejtöréssel azt láthatjuk, hogy ez tovább optimalizálható.  Azon kívül, hogy fel kell iratkoznunk a kattintásokra, még a showLayer-t is meg kell írni, amiről eddig még nem esett szó. Szerencsére a jQuery segítségével ez sem bonyolult:

$(‘#popup’).show();

Mindössze egy sor, amiben viszonylag nehéz hibázni. Vigyük tovább, ne elégedjünk meg ennyivel, ha lehetséges legyen még kevesebb! Valamint az sem elhanyagolható szempont, hogy jelen esetben a js kódunk most ki van szolgáltatva a html attribútumnak. Amennyiben az megváltozik, és nem lesz ilyen id, azt ugyan lekezeli a jQuery, de elég valószínű, hogy nem lesz  működőképes.

Nos, az egysoros kódnál csak a nulla soros kód a rövidebb 🙂  Ráadásul sokkal nehezebb is hibázni benne. Teljesül is az hogy nem dolgozunk és nem hibázunk. Lássuk, hogy hogyan lehet 0 sor javascripttel a fenti specifikációt megvalósítani.

álljon itt a teljes javascriptes forráskód 🙂


Próbálkoztunk, de ezt azért elég nehéz elrontani. Ebből adódik, hogy a kódminőséggel nem lesz bajunk, viszont akkor mitől is lesz működés? A válasz pofon egyszerű: az angularjs-től.

Természetesen valahol lennie kell a működtető kódnak. A jQuery esetén lemondtunk az if-ekről, és megbíztunk a jQuery-ben, feltételezve hogy ott helyesen implementálták azokat, így most az angular-ban bízzunk meg. Továbbra is kérdés: honnan tudja, hogy milyen működést képzeltünk az adott html oldalra? A válasz kézenfekvő: magából a html-ből.

Fussunk végig a markup-on, azonnal kiszúrjuk csak az első két gombot, amivel elfogadjuk, vagy nem fogadjuk el a feltételeket:

<div>elfogadom</div>
<div data-ng-click=”showPopup=true;”>elutasitom</div>

Ugyan elsőre hasonlit kicsit a html onclick-re, viszont itt annál sokkal többről van szó. Ha ott beállitottunk volna egy változót, attól még nem történt volna meg a csoda. Ezt a csodát kétirányú bindolásnak nevezzük.

Nézzük tovább a html kódot:

<div data-ng-show=”showPopup”>
<!--ez itt a popup tartalma-->
<div data-ng-click=”showPopup=false;”>Tényleg elutasítom</div>
<div data-ng-click=”showPopup=false;”>Meggondoltam magam</div>
</div>

… és voálá: azonnal működővé, és látszólag élővé vált a statikus html oldalunk. Egészítsük ki egy bezár gombobbal:

<div data-ng-show=”showPopup”>
<div data-ng-click=”showPopup=false;”>X</div>
ez itt a popup tartalma
<div data-ng-click=”showPopup=false;”>tényleg elutasítom</div>
<div data-ng-click=”showPopup=false;”>meggondoltam magam</div>
</div>

Persze ez még csak a látvány része volt. Akár megnyílt a pop up, akár nem, semmi sem történt a látványelemeken kívül. Összehasonlításképp lássuk  mennyi javascriptet irtunk ehhez:

Most minden különösebb bevezető helyett álljon itt a kód ami a tényleges működést is megcsinálja:

popup::

<div data-ng-show=”showPopup”>
<div data-ng-click=”showPopup=false;”>X</div>
ez itt a popup tartalma
<div data-ng-click=”conditions=false;showPopup=false;”>tényleg elutasítom</div>
<div data-ng-click=”showPopup=false;”>Meggondoltam magam</div>
</div>

feltételeknél a gombok:

<div data-ng-click=”conditions=true;” data-ng-init=”conditions=true;”>elfogadom</div>
<div data-ng-click=”showPopup=conditions;”>Elutasitom</div>

Logikai magyarázat:

A showPopup változó vezérli a felugró layer láthatóságát.

A conditions változó pedig azt jelzi, hogy elfogadtuk-e a feltételeket.

Alapértelmezetten elfogadottnak tekintjük, ez szerepel a data-ng-init attribútumban. Valamint ha az elfogadom gombra kattintunk, akkor mindenképpen true lesz.

Ha viszont az elutasítom gombra kattintunk, akkor… nos, ha már egyszer elutasítottuk, akkor nem kell újra megkérdezni hogy tényleg, ezért showPopup-nak éppen a conditions értékét adva értékül, le is írtuk ezt a feltételt: ha már elutasította akkor nem kell pop up, ha pedig elsőként kattint a gombra, akkor feljön a pop up, mivel a showPopup értéke true lesz. Magán a layer-en csak egy újdonság van: a tényleg elutasítom gombon történt kattintás a conditions változót is beállítja.

Hát nem nagyszerű? Kétféle html attribútum, két – amúgy máshol nem létező – változó, pár értékadás, és máris működik az egész.

De mi a helyzet a dizájnnal? Pl.: ha jelölni szeretnénk egy css class-al azt hogy már felesleges az elutasítom gombra kattintgatni, akkor azt is nagyon egyszerűen megtehetjük:

<div data-ng-click=”showPopup=conditions;” data-ng-class=”{inactive:!conditions}”>elutasitom</div>

értelemszerűen ha a conditions változó értéke false (pontosabban falsy) akkor kap egy inactive css class-t.

Viszont valami még kimaradt: ha ezeket a html-eket megirod, még nem fog működni. Sajnos a dolog mégsem ennyire egyszerű. A működéshez az alábbi három lépést még el kell végezni:

  1. be kell húzni az angular.js-t
  2. definiálni kell az app-ot: <html data-ng-app=”popupdemo”>
  3. valamint meg kell kérni az angulart-t hogy foglalkozzon a mi app-unkkal

 

Következzen akkor a teljes forrás, ami már garantáltan működik:

<html data-ng-app="popupdemo">
<head>
  <title>shiwaforce popup demo</title>
  <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  <script>angular.module('popupdemo',[]);</script>
</head>

<body>
  <div data-ng-click="conditions=true;" data-ng-init="conditions=true;">elfogadom</div>
  <div data-ng-click="showPopup=conditions;" data-ng-class="{inactive:!conditions}">elutasitom</div>
  <div data-ng-show="showPopup">
  <div data-ng-click="showPopup=false;">X</div>
  ez itt a pop up tartalma
  <div data-ng-click="conditions=false;showPopup=false;">tényleg elutasítom</div>
  <div data-ng-click="showPopup=false;">meggondoltam magam</div>
</div>
</body>
</html>