A "lib" könyvtárban lévő jar-fájlokra van szükség, de mivel nem használunk Velocity-t,
a wicket-velocity.jar -t semmiképpen se tegyük
be a projektbe a többi library közé, mert hibát dob az Apache Velocity hiánya miatt.
Amikor egy markup megjelenik a böngészőben akkor a hozzátartozó java osztály példányosítva lesz, és ez a példány
ott marad a serveren amíg a view-t látjuk a böngészőben. Amikor ezt a view-t elhagyjuk
(setResponsePage()-et hajtunk végre),
akkor a page példány is megsemmisül.
A markup a wicket:id="azonosító" alapján talál össze a java kóddal, számítanak az azonosítóban lévő
kis/nagy betűk is.
Azonosítónak ne használjuk az "id" -t, mert ez másra van fenntartva, furcsa működést eredményez.
A markup-ba ne írjunk "id" tag-et, mert a Wicket felülírhatja saját értékével pl: id="id28"
Ha mégis általunk megadott id-re van szükségünk (pl. javascript elérés miatt), akkor használjuk a Component osztály
setMarkupId(...) és setOutputMarkupId() metódusát.
A markup input elemei kapnak "name" tag-et, és a Wicket a wicket:id értékét írja bele (felülírja).
Ha egy komponens később van definiálva mint ahogy hivatkozni akarunk rá (pl. form onSubmit() metódusában),
akkor tegyük ki példányváltozóként,
így bárhol lehet rá hivatkozni. Lokális változóként nem jó mert akkor final-ra kellene deklarálni.
A "Wicket in Action" ebook (2009-es kiadás) adott lapjára való hivatkozás ebben a leírásban: WIA.oldalszám
A letöltött Wicket csomagban lévő "wicket-examples-xxx.war" -ra való hivatkozás ebben a leírásban: WEX -> ...
Az itt leírt példában az alkalmazásunk elérési url-je -> http://localhost:8080/wicketapp
tehát az alkalmazásunk context root-ja legyen "wicketapp"
Egy wicket-es alkalmazás normál servletet is tartalmazhat. Ezzel a normál servlettel is meg lehet valósítani
az alacsony szintű kommunikációt. Ha egy kliens a sevletnek byte-sorozatot küld akkor PUT metódussal
kell ezt megtennie, POST esetén nem kapja meg az adatokat a servlet (a WicketFilter lenyeli az adatokat) !
Szabvány egy wicket alkalmazásban:
Legyen az alkalmazáson belül egy aa.MyApplication osztály (extends WebApplication),
erre "MyApplication" néven hivatkozunk.
Legyen az alkalmazáson belül egy aa.MySession osztály (extends WebSession), erre "MySession" néven hivatkozunk.
A statikus resource-ok (css,image,js) legyenek egy "fixed" package-en belül, és ez a package tartalmazzon
egy "Fixed" nevű osztályt, hogy erre hivatkozva tudjuk elérni a statikus erőforrásokat.
ajax
RadioChoice esetén ha ajaxos működést akarunk rádiógomb kattintásra, és szeretnénk tudni mi a rádiógomb értéke,
akkor AjaxFormChoiceComponentUpdatingBehavior -t kell használnunk, nem pedig AjaxFormComponentUpdatingBehavior -t !
Ha egy komponenshez ajax behavior -t rendelünk (pl. onchange eseményre ajax request-et produkál),
akkor kizárólag ennek a komponensnek a model update-je történik meg a serveren.
A képernyőn lévő többi komponens épp aktuális értékéhez nincs mód hozzáférni.
Ajax respons-nál viszont módosíthatjuk a kívánt komponensek modeljét,
és ha ezeket újra renderelni akarjuk (target-ben megadjuk),
akkor ezek a komponensek a model értékük alapján lesznek megjelenítve.
Egy AjaxLink, AjaxFallbackLink esetében egyetlen komponensnek sem történik meg a model update-je,
így tehát a képernyőn lévő épp aktuális értékek nem hozzáférhetőek !
Az ajax response-nál a target-ben megadott komponensekre általában használni kell a
metódusokat, ezek leírása itt található: Component
Ha egy oldalon ajax-os funkció működik akkor megjelenik az "wicket ajax debug" link.
Ennek letiltásához a MyApplication.init()-be ez kell:
Amíg egy hosszú folyamat tart (akár ajax-os, akár nem), a többi ajax funkció nem tud futni, tehát várakoznak,
így nincs párhozamos ajax végrehajtás !
AbstractAjaxTimerBehavior osztály használata:
Az onTimer() metódusban írható le mi történjen adott időközönként. Akár más lapra is irányíthatjuk a vezérlést,
frissíthetünk komponenseket stb.
Fontos hogy ha le van tiltva egy komponens (setEnabled(false)), vagy nem látható (setVisible(false)),
akkor nem működik rá a AbstractAjaxTimerBehavior, hiába van hozzárendelve. Viszont amikor a komponenst
engedélyezzük, láthatóvá teszük,
akkor automatikusan elindul az AbstractAjaxTimerBehavior funkciója.
Long process kezelése:
Mivel nincs párhuzamos ajax végrehajtás, a módszer a következő:
egy AjaxButton ellenőrzi az űrlapot. Ha helyes, akkor letiltja magát, és láthatóvá teszi azt a komponenst
melyhez egy ajax-timer kötődik
(lásd: AbstractAjaxTimerBehavior osztály)
A timer csak ekkor fog aktivizálódni, hiszen a komponens eddig nem volt látható. A gomb ezután elindít egy
külön szálat és mást nem csinál, így biztosítva hogy a timer vegye át a vezérlést. A külön szál jelzi hol tart
és van egy exception jelzője is ha hiba keletkezik benne. A timer pedig vagy a kiírja időközönként hol tart
a szál végrehajtása, vagy pedig ha a szál jelzi hogy hiba keletkezett benne akkor a timer is dob egy hibát,
a vezérlést a hibaoldalra irányítva. Ha a szál normálisan végrehajtódott akkor a timer a vezérlést
egy új oldalra irányítja.
Példa arra amikor az egyik html lenyíló lista változtatásakor a másik lenyílóban átírjuk az elemeket:
Ebben az esetben csak a szamtipusChoice komponensnek módosul a modellje, a többi komponens értékét nem küldi
fel a serverre.
Csak akkor módosul a model ha a konverzió/validáció megengedi. Ha pl. setRequired(true) van
beállítva a komponensre,
és kiürítjük a tartalmát akkor a változás ellenére nem fut le az ajaxos onUpdate() metódus!
Önmagát frissítő komponens, ami ebben a példában egy óra megjelenítését végzi.
A markup egy egyszerű <span> tag.
AjaxButton
Segítségével egy form-ot ajaxos módon lehet submit-álni. Így beállítható hogy a form nem frissül
a képernyőn csak a a feedback panel. A legnagyobb előnye akkor van amikor az űrlapon file upload mező is van,
ugyanis ennek tartalma elveszne egy normál submit + újlap(hibaüzenetekkel) generálás miatt,
ugyanis a böngésző mindig kiüríti ezt a mezőt.
Markup (a formon belül kell elhelyezni):
Java:
AjaxEditableChoiceLabel
Ez a komponens egy sima Label-ként látszik, de ha rákattintunk átváltozik lenyíló html listává
amiből választhatunk.
Java:
AjaxEditableLabel
Ez a komponens egy sima Label-ként látszik, de ha rákattintunk, átváltozik beviteli mezőre míg szerkesztjük.
A szerkesztést enter-rel, vagy esc-vel tudjuk befejezni, az utóbbi esetén elvetjük a szerkesztést.
Meg lehet változtatni a beviteli mező szélességét, előírhatjuk hogy ha
kezdetben a Label üres akkor milyen karakter látszódjon a helyén hogy rá lehessen kattintani.
Java:
AjaxLink
Ajax hívást megelőző confirm üzenet beállítása:
AttributeModifier
Az AttributeModifier egy markup tag attribútumának beállítására szolgál.
Ugyanezt csinálja a SimpleAttributeModifier is, de ez egyszerűbb mert ezzel csak string adható meg attribútum
értékére, nem pedig egy model.
Megoldható vele hogy egy html táblázaton belül a páros és páratlan sorok máshogy nézzenek ki,
vagy egy gombhoz javascript confirm köthető:
Az AttributeModifier-nek létezik egy addAttributeIfNotPresent argumentuma.
Ezt érdemes true-ra venni, így a markup-ban nem is kell ugyanilyen attribútumnak lennie, hozzáadja.
Egy HTML tag attribútumát törölni is lehet, például egy <a href="#"> esetén a teljes href törlése:
AutoCompleteTextField
Működés: egy text mezőbe gépelve a szöveget, ezt támogatja egy lenyíló kisablak a
lehetséges értékekkel (pl: településválasztó)
Markup szükséges css része (lásd a forrásnál):
Markup html része (csak egy normál text input):
Java:
AutoCompleteTextField osztályt kell használni, amelyben felüldefiniáljuk getChoices() metódust.
Ez a metódus előállítja a lenyíló kisablakban az elemeket, a mezőbe lévő tartalom alapján.
A metódus minden egyes karakter gépelése után lefut.
Az AutoCompleteTextField működése szabályozható az AutoCompleteSettings osztállyal.
Ha például azt szeretnénk hogy üres mező esetén is megjelenjenek a lehetséges elemek a lefelé nyílra:
Forrás: WEX -> ajax -> Auto-Complete TextField Example
Border
A Border a Panel-hez hasonló, saját markup-pal rendelkezik, de annyiból különbözik hogy a border
belsejét a felhasználó markup határozza meg.
Lásd: Wicket user guide 30. oldal.
bug
DateTextField bug ??? Ez nem Wicket probléma, ugyanaz a project más környezetben nem produkálja, talán csak Windows-os
szerveren jön elő.
A mezőbe gépelt érték helyett mást kapunk vissza a model-ben. A jelenség csak az 1891.10.01 vagy ennél régebbi
dátumoknál jelentkezik.
Ráadásul ezt a dátumot be sem lehet vinni, mert érvénytelennek érzékeli. Az ennél régebbi dátumok esetén,
minél régebbre megyünk vissza
annál nagyobb az elcsúszás, akár 6 nap is lehet a különbség a gépelt, és a model-ben megkapott dátum között.
A wicket-1.4.17 lecserélése 1.4.19-re, és a joda-time-1.6.2 lecserélése joda-time-2.0 -ra nem oldotta meg a problémát.
Page mount "/" paraméterrel bug:
Ha egy page-re van page mount, és ennek a lapnak paramétert adunk át melyben "/" jel szerepel akkor üres
lapot kapunk, az oldal nem működik.
Amiatt van a probléma hogy a paraméterek "/" jellel vannak elválasztva, és a paraméteren belüli "/" hibásan
kezelődik a mount-olt page-nél.
Megoldás: speciális page mount használata, lásd: page mount
Model in session bug (1.4.17, 1.4.19, 1.4.20 verzióban is):
Ha egy űrlap mezőinek model-jét session-ben tároljuk akkor fordul elő ez a hiba. Ha erről a lapról
elnavigálunk egy link-kel,
majd a böngésző back-gomjával visszatérünk az űrlapra, vagy az űrlapon popup ablakot nyitunk, és azt bezárva
térünk vissza az űrlapra,
akkor innentől az űrlap hibásan működik: a submit gomb hatására a form-mezőkben lévő adatok nem íródnak be a
model-jükbe,
így a model a régi adatot tartalmazza.
Megoldás: a Session objektumot máshogy kell megkapnunk, lásd: Session
Popup session bug:
Ha két lap van nyitva, melyből az egyik normál a másik ennek a popup-ja, akkor mintha nem ugyanazt a session-t látnák,
más-más a kapott session objektum.
Megoldás: a Session objektumot máshogy kell megkapnunk, lásd: Session
Button
onSubmit() metódus: akkor érdemes használni ha a form több gombbal rendelkezik,
különben elég a Form onSubmit()-ja.
Nem fut le ha a form invalid.
setDefaultFormProcessing(boolean) metódus: végrehajtódjon-e a normál form processing(konverzió, validálás,
model update).
False esetén direktben meghívódik a Button.onSubmit(), és ilyenkor a Form.onSubmit()-je nem hajtódik végre.
Tipikusan cancel gombnál állítjuk false-ra.
Cancel button:
Form invalid kitöltés esetén csak a Form.onError() metódusa fut le (kivétel a cancel gomb, lásd előző bejegyzés).
Form valid kitöltése esetén előszőr a Button.onSubmit() metódusa, majd a Form.onSubmit() metódusa fut le.
CheckBox
Markup:
Java:
CheckBoxMultipleChoice
Html többszörös checkbox megvalósítása, egy komponensként:
kutya
macska
zsiráf
Markup:
Java:
A check-elt elemek a "valasztottak" változóba kerülnek, melynek List-nek kell lennie.
Nemcsak DDI elemekkel lehet megvalósítani, hanem bármilyen objektummal (pl. String elemekkel).
A "lehetosegek" listában lévő elemekből amiket a felhasználó check-el, azt kapjuk meg a "valasztottak" listában.
Azok az elemek melyek kezdetkor benne vannak a "valasztottak" listában, azok már check-elve jelennek meg a felületen.
A setSuffix(), setPrefix() metódusokkal lehet szabályozni a checkbox-ok elrendezését, pl. vízszintesen: setSuffix("")
Component
setMarkupId(String)
Html-komponens "id" attribútumának megadása. Ezzel felül lehet bírálni azt amit a Wicket adott volna.
Hogy a html-be biztos be is kerüljön, használjuk még a setOutputMarkupId(true)-t is.
setOutputMarkupId(boolean)
Html-komponens "id" attribútumának írása java kódból, és így a markup-ban szereplő "id" felülírása.
False esetén ha a markup nem tartalmazott "id" attribútumot akkor nem lesz a végleges html-ben "id".
Kötelező true argumentummal használni ha a komponenst ajax-os request frissíti
(AjaxRequestTarget.addComponent()-nél használjuk), ugyanis ilyenkor az "id"-vel azonosítja az ajax a komponenst.
setOutputMarkupPlaceholderTag(boolean)
Placeholder tag megjelenítése/eltüntetése abban az esetben amikor a komponens nem látszik a képernyőn.
True-ra kell állítani ha ajax-szal szeretnénk a komponens láthatóságát ki/be kapcsolni.
Ha a placeholder nem létezne, akkor egy nem látható komponenst nem lehetne láthatóvá tenni, hiszen nem lehetne
rá hivatkozni.
setVisible(boolean)
Html-komponens láthatóságának beállítása a html felületen. Ha letiltjuk a láthatóságot akkor a gyerek elemek sem
jelennek meg!
setEnabled(boolean)
Html-komponens szerkeszthetőségének engedélyezése/tiltása. Ha a komponenst letiltjuk, akkor a gyerek komponensei is
letiltásra kerülnek!
setEscapeModelStrings(boolean)
A komponens model string-jének escape-elve való kiírása a html felületre. Ez különösen Label komponens
esetén hasznos, például vastagbetűs label:
error(), debug(), fatal(), info(), warn()
Feedback message rendelése a komponenshez.
setResponsePage()
Vezérlés átirányítása új lapra.
Például ebben az esetben ha MyPage konstruktor fogad PageParameters-t, nem null-t, hanem egy üres
PageParameter-t kap:
Például PageParameter átadása MyPage-nek:
Például nem az osztályt megadva hanem egy kész példányra átadva a vezérlést. Ezt a verziót óvatosan használjuk,
előre ne fusson le a new operátor:
setRenderBodyOnly(boolean)
Html-komponens befoglalójának megjelenítése/eltüntetése. Default értéke false. True esetén csak a belső "body"
jelenik meg a html kimenetben.
Például ha a markup:
és a java:
akkor csak az "árvíztűrő" jelenik meg <span> befoglalók nélkül.
IModel
A komponenshez egyértelműen hozzárendeljük a model-jét.
Az IModel interface-nek 2 metódusa van:
IConverter
Ezt legtöbbször nem rendeljük hozzá a komponenshez így a default converter-ek működnek.
Az IConverter interface-nek 2 metódusa van:
Ha a komponenshez saját konvertert szeretnénk rendelni akkor két lehetőség van:
1. Felüldefiniáljuk a komponens getConverter() metódusát, mely a saját konverterünket adja vissza.
2. Általánosan az egész alkalmazásra állítunk be konvertert, és ez fog konvertálni mindig ennél az adattípusnál.
Ezekre példa: WIA.323
Figyelem:
RadioChoice, DropDownChoice:
Nem hívódik meg a getConverter() metódusa! Mindig olyan típusúnak kell lenni a modeljének, amilyen típussal
feltöltjük a választólistáját.
Checkbox:
Nem lehet felüldefiniálni a getConverter() metódusát, mert az final! Így tehát a modelje mindig boolean legyen.
onComponentTag()
Ennek a metódusnak a felüldefiniálásával lehet módosítani a html-tag attribútumait.
Például ha a wicket beletesz valami speciális dolgot egy link onclick attribútumába, akkor így lehet elé beszúrni
egy confirm üzenetet:
CompoundPropertyModel
A webpage komponens hierarchiában egy felsőbb szintű komponens modelje, melyet az alsó szintűek használnak.
Pl. egy form esetén neki ez a modelje, és a form gyerek elemeinél nem kell már a modelt definiálni.
A gyerek elemek id-je lesz a property expression. Amennyiben mégsem ezt szeretnénk property expression-nek,
használjuk a bind() metódusát.
bind() példa:
container
A container (MarkupContainer osztály) olyan elem amely más komponenseket(component) tud magába foglalni.
A komponenseket a container add() metódusával lehet hozzáadni. Egy container-en belül a hozzáadott
komponensek id-jének
egyedinek kell lennie, ezért az egész weblapon nem szükségesek az egyedi id-k ha más más container-en
belül vannak.
A get() metódussal megkapható a container-en belüli komponens, például:
context path
Context path lekérdezése:
Ha az alkalmazás proxy mögött fut, akkor a context path eltérhet a böngészőből hívott url-től !
DateLabel
Egy java.util.Date megjelenítése egy Label-ben a kívánt formában ezzel lehetséges, például:
DateTextField
Dátum típusú adat felvitelére szolgál TextField formában. Például:
ahol a model-ben java.util.Date típusú a változó.
A használathoz szükséges a "joda library", mely letölthető innen:
joda library
Dátumválasztó image hozzáadása:
deployment mode
Az alkalmazás képes "development" és "deployment" módban is futni. Fejlesztéshez az előbbi,
éles alkalmazásnál az utóbbi a hasznosabb.
Az üzemmód beállítása a MyApplication.getConfigurationType() felüldefiniálásával történik:
Deployment módban sokkal kevesebb hibaüzenetet kapunk, csak egy rövid "internal error" lap jelenik meg.
De lehetőség van a részletes hibaüzenetet megkapni a MyApplication.init()-be ezt írva:
vagy saját error page-et használhatunk: expired & error page
Deployment módban a html oldalból kikerülnek a "wicket"-es attribútumok, így erre nem hivatkozhatunk javascript-ből !
DropDownChoice
Html 1-soros lenyíló select megvalósítása:
Markup:
Java:
Ahol a getVarosList() egy List<DDI> elemmel tér vissza.
A saját DDI osztályunk pedig két tagú:
és belül tartalmazza a saját ChoiceRenderer-jét.
Üres elem engedélyezése a listában:
Meghatározza hogy a lenyíló értékei között legyen-e null érték is (hiszen ezt nem kell beletennünk a lista
elemei közé)
true -> a lenyílóban automatikusan megjelenik egy üres érték is (így nem jön fel a "válassz egyet" üzenet)
false -> a lenyílóban nem jelenik meg az üres érték, kivéve ha a model null-on áll (feljön a "válassz egyet"
szöveg is a listában)
Lenyíló lista elemeinek megváltoztatása:
Amikor a lenyíló listából a user az üres elemet választja ki, akkor a modell-be null kerül,
így tehát ennek az id-jére sem hivatkozjatunk
mert NullPointerException-t okoz.
A DropDownChoice nem alkalmas arra hogy <select>-en belül <optgroup>-ot valósítsunk meg,
erre a Select és SelectOptions osztályok alkalmasak.
Forrás: WIA.178
encoding
A wicket default módon UTF-8 -ban olvassa a request-et, az url-t, és írja a response-t.
Figyelem: a böngésző az url-sorába gépelt ékezetes karaktereket nem utf-8 kódolásra alakítja !
UTF-8 kódolásssal az "árvíztűrő" szövegnek így kell kinézni:
Az encoding átállítása nem ajánlott mivel az UTF-8 a legjobb, de a RequestCycleSettings osztály
setResponseRequestEncoding() metódusa állíthatja.
Az átállításhoz a MyApplication.init()-be ez kell:
expired & error page
A default működésnél a session lejártakor egy "page expired" lapra jutunk, illetve exception keletkezésekor
pedig egy default hiba kiíró lapra. Ezek helyett más lapokat készíthetünk, és ezekre irányíthatjuk át a vezérlést.
Több módszer is lehetséges de a legjobban használható MyApplication.newRequestCycleProcessor() felüldefiniálása:
Az exception kezelő csak egyszer hívódik meg! Ha a kezelőben is exception keletkezik akkor egy külső kezelőhöz
jut el az exception, például egy Tomcat hibalap jelenik meg az exception szövegével.
ExternalLink
Külső, alkalmazáson kívülre mutató link.
Megvalósítás egyszerű módon, mikor a link csak egy sima szöveg:
Markup:
Java:
Megvalósítás összetett módon, amikor a linken belül több dolog is van (pl. szöveg + kép):
Markup:
Java:
FeedbackPanel
Egy olyan feedbackpanel mely csak akkor jelenik meg (a körítésekkel) ha tartalmaz információt:
Markup:
Java:
Egy FeedbackPanel-ben megjelenő üzeneteket szűrhetjük, így megoldható hogy egy mező mellett csak a
hozzátartozó üzenetek jelenjenek meg, pl:
esetén a "szoveg_feedback" azonosítóval ellátott feedback panel csak a szovegField-hez tartozó üzeneteket
jeleníti meg.
A panelre írhatunk a debug(), error(), fatal(), info(), warn() metódusokkal, az error()-t használjuk default-ként.
Amennyiben egy adott form-komponensnek hívjuk meg ezen metódusait, akkor a komponenshez tartozó message-et
állítunk elő.
Forrás: WIA.198
File download
ResourceLink módszer
A weboldalon egy link található, mely mögött egy resource van.
Ha dinamikusan készítünk excel-t vagy pdf-et, akkor az a módszer járható hogy elkészítjük a fájlt,
majd ezt adjuk meg a WebResource leszármazottnak.
Markup:
Java:
Forrás: WIA.253
RequestCycle módszer
Itt egy eljárással direkt írunk a respons-ra, ez sokkal dinamikusabb mint a ResourceLink módszer.
Így pl. egy gomb vagy link futásidőben eldöntheti hogy egy html lapot vagy egy bináris fájlt szolgáltasson,
és lehetőség van arra is hogy egy mount page rögtön bináris fájlt adjon vissza, a paramétere függvényében.
Java:
Ha a letöltendő fájl a webalkalmazásunkon belül van, például közvetlenül a "Web Pages" alatt akkor így lehet elérni:
File upload
Markup:
Java:
Ha magyarítani akarjuk a fájl mérete és a feltöltés sikertelensége miatt keletkező hibaüzenetet,
azt nem helyezhetjük el a globális message-ek közé, csak a page saját properties fájljába,
és hivatkozni kell a form id-re (itt például "form1"):
Forrás: WEX -> upload
Form
Form validálás:
Akkor van rá szükség amikor több mező összefüggését kell validálni. Felül kell definiálni a form.onValidate()
metódusát.
Mivel ekkor még nincs benne az adat a modelben, a form komponensek getConvertedInput() metódusaival férünk hozzá.
Azért ez a legjobb megoldás egy form validálására, mert ha például egy xesj-tabpanel formon kívüli
SubmitLink.onSubmit()
metódusa elnavigálna az oldalról, akkor ezt a form.onValidate()-tel lehet megakadályozni.
Ha csak a form.onSubmit() metódusa adna ki error()-t, sajnos akkor is megtörténne az elnavigálás a SubmitLink által,
hiszen a fom valid-nak lett kiértékelve.
Példa:
FormComponent
Működés: 3 réteg létezik: kliensoldalon a html mező, serveroldalon a FormComponent, és a FormComponent modelje.
Ha a mezőbe gépelt érték helyes (konverzió, validáció helyes), akkor submit hatására az érték bekerül a modelbe,
és a FormComponent-ben nincs (nem marad) raw-input (hasRawInput() == false; getRawInput() == null).
Ha a mezőbe gépelt érték hibás (konverzió vagy validáció hibás), akkor submit hatására az érték nem kerül a modelbe,
viszont a FormComponent-ben van raw-input (hasRawInput() == true; getRawInput() == "...").
Amikor egy FormComponent-t meg kell jeleníteni html mezőként akkor a megjelenő értéket 2 helyről veheti a Wicket:
Ha van raw-input akkor a FormComponent-ből veszi (getRawInput()), ha nincs akkor a model-ből.
Raw-input törlése: akkor szükséges ha a html mező megjelenítésekor biztos a
FormComponent model-jében lévő értéket akarjuk megjeleníteni.
Ilyen eset lehet amikor egy AjaxLink akarja a mező tartalmát átírni:
Ha egy Form-nak hajtjuk végre clearInput() metódusát akkor a gyerek elemekre is megtörténik a clearInput().
FormComponent értékének lekérdezése string-ként:
Ha létezik raw-input, akkor azt adja vissza, különben a model értékét adja vissza string formájában.
Validációs üzeneteknél megjelenő mező megnevezés (mező label) beállítása:
Az üzenetek szövegében lehet rá hivatkozni ${label} formájában.
Html format
Alapesetben az xhtml-es formát használjuk, de lehetőség van sima html használatára is.
Sima html formátum használatánál be kell állítani milyen karakterkódolással olvassa be a wicket a html fájlt,
így pl. UTF-8 kódolás esetén a MyApplication.init()-be ez kell:
Definiáljuk a html tag-nél a name space-t is, hogy a netbeans editor ne jelezzen hibát.
Egy bevált HTML5 formátum:
HttpServletRequest
A HttpServletRequest objektum lekérdezése:
A HttpServletRequest objektumból meghatározható a kliens IP-címe, a kapott sütik, a header, a context path, ...
Lehetséges a hívás típusának (GET,POST) meghatározása, és utóbbi esetén a http-body InputStream-mel kiolvasható.
Label
A Label-hez tartozó markup szinte bármi lehet, ezek belsejét a Label ki tudja tölteni, így például javascript
kódot is elő lehet állítani
dinamikusan:
Link
Markup:
Java:
Az onClick() metódust kötelező definiálni, itt van leírva mi történik a link-re kattintáskor.
A Link nem submit-álja a formot, azt a SubmitLink-kel lehet megvalósítani.
Ha a link szövegét szeretnénk átírni akkor egy belső elemet kell a markup-ba beágyazni,
a Link 2. paramétere (model) nem hat a szövegére.
ListView
Markup:
Java:
A ListView minden List-et képes megjeleníteni (tetszőleges típusú elemei lehetnek).
Ezekhez az elemekhez a hozzáférés az item.getModelObject()-tel történik.
Az itt látható markup-ban az egész <div>...</div> ismétlődni fog, tetszőleges sokszor, mindenképpen kell
egy legkülső "befogó elem" ami a belsőket egybefogja (legalább egy <span>).
A "befogó elem" is állítható a java kódban, rá az "item"-mel hivatkozunk a fenti példában.
A populateItem() metódusban az item.getIndex() metódussal kérhetjük le hányadik sorban vagyunk,
ezzel megvalósítható a páros-páratlan sor eltérő megjelenítése.
A lista elemei lehet pl. Map, de ha input elemek is vannak a listában akkor egy saját osztály
példányai legyenek az elemek,
ez jobban kezelhető.
Ha formon belül használjuk, és tartalmaz input elemeket akkor mindenképp használnunk kell a
setReuseItems(true) beállítását,
különben invalid form esetén nem tartja meg az input elemek tartalmát ! Ha viszont a setReuseItems(true) beállítást
használjuk és változtatunk a ListView model-jén, akkor előtte el kell távolítani belőle a gyerek komponenseket.
Lásd az API doc -ban a ListView leírásánál.
A ListView model-jének a getObject() metódusa annyiszor fut le ahány sor van (a populateItem() metódus miatt)
ezért ne rakjunk mögé olyan IModel-t melynek getObject() metódusa adatbázis select-et hajt végre.
Inkább használjuk a fenti példában látható PropertyModel-t, vagy egy sima List-et melyet később megváltoztathatunk
a ListView setList() metódusával.
Locale
Ha magyar környezetet használunk akkor a MyApplication.init()-be állítsuk a Locale-t magyarra:
Lehetséges a MySession-ben is locale-t állítani, de ez nem lesz globális az egész rendszerre,
mert ez csak a session-locale -t állítja be:
amennyiben ezt a konstruktort hívja a MyApplication.newSession() metódus
Azokon a helyken (komponenseknél) ahol nem a magyar locale a kívánatos, ott állítsuk be arra a komponensre
helyileg.
Mivel a komponensnek csak getLocale() metódusa van - setLocale() nincs - így azt kell felüldefiniálni.
login
Feladat: ha a user nincs bejelentkezve akkor védett lap kérése esetén a login lapra kell irányítani,
a nem védett lapokat viszont bármikor megnézheti.
1. megoldás: készítünk egy WebPage leszármazottat, legyen a neve ProtectedPage.
A védett lapok legyenek a ProtectedPage leszármazottai,
a nem védet lapok WebPage leszármazottai. Mivel a ProtectedPage üres konstruktora mindig lefut, ez ellenőrzi
hogy be van-e a user jelentkezve
(pl. a MySession példányunkba bejegyeztük-e a usert), különben átirányítjuk a kérést a login lapra, így:
A módszer akkor is működik ha a védett osztályt mi példányosítjuk és így fut rá a fenti exception-re.
2. megoldás: a védett és nem védett lapok is egy közös (legyen BasePage) leszármazottai, a BasePage konstruktora
kapja meg paraméterként
hogy védett lapként kell-e viselkednie, és ellenőrizze-e a user bejelentkezését.
Forrás: WEX -> authentication | WIA.294
logout
Általában csak annyit csinálunk, hogy a session-ből kitöröljük a "bejelentkezett user" objektumot.
Ha végrehajtunk a session objektumon invalidate() metódust is, akkor a következő request PageExpiredException-t okoz,
így a vezérlés arra az oldalra kerül amit megadtunk ennek az exception-nek a lekezelésénél.
Példa:
markup inheritance
A markup inheritance a <wicket:child>, <wicket:extend>, <wicket:head> elemekkel valósítható meg.
A szülő markup egyetlen <wicket:child/> elemet tartalmazhat, mely jelzi hogy ide kell beilleszteni a
gyerek markup-ot.
A gyerek markup-ban a <wicket:extend>...</wicket:extend> közötti elemek lesznek beillesztve a
szülő markup-ba
a <wicket:child/> helyére, illetve ha a gyerek markup <head> része
tartalmaz <wicket:head>...</wicket:head>
elemet is, akkor a közötte lévő markup is beillesztődik a szülő <head> részébe.
A szülő-gyerek markup-nak megfelelően a gyerek java osztály leszármazottja a szülő java osztálynak.
messages properties
A wicket-1.4.17.jar fájlban megtalálható az Application_hu.properties magyar üzenetekkel,
ez jó kiindulópont a saját üzenetek kialakításához a MyApplication.properties fájlunkban.
Adat kiolvasása programmal a messages properties fájl(ok)ból:
Például legyen egy bejegyzés a MyApplication.properties fájlban:
Ennek megjelenítése egy Label-ben:
(ha az üzenetnek nincsenek paraméterei, akkor a StringResourceModel konstruktorban nem kell megadni a Model-t)
ModalWindow
A ModalWindow egy felugró ajax-ablak, de nem használ akkora erőforrást mint egy új böngészőablak.
Ameddig le nem zárjuk, a felhasználó nem fér hozzá a hívó laphoz.
Javascript nélkül tudunk beleírni a hívó oldalba.
A hívó oldalra való hivatkozást átadni a hívottnak csak PageReference segítségével történhet, különben
nem tudjuk módosítani a hívó oldal komponenseit.
Meghatározza milyen tartalommal töltődjön fel a ModalWindow:
Az alábbi metódus csak a ModalWindow lezárásakor fut, és meghatározza mit kell frissíteni a hívó oldalon.
Így tehát ameddig a ModalWindow-t nem zárjuk le, nem lehet a hívó oldalon semmit módosítani.
Az alábbi metódus akkor fut, ha a ModalWindow-t a jobb felső "X"-szel zárjuk.
True visszatérési érték esetén a ModalWindow lezárható "X"-szel, false esetén nem.
ModalWindow ablak felirata:
Beállítható milyen cookie névvel tárolódjanak a ModalWindow méret-pozíció paraméterei.
Ennek segítségével ha a ModalWindow később újra megnyílik, az előző mérettel és pozícióval fog megtörténni.
Mintapélda: a hívó aktiválja a ModalWindow-t, mely beleír a hívó "nev" mezőjébe.
Többsoros Label komponens. A sorváltást a "\n" karakter biztosítja.
Ne használjuk, mert nem jól jeleníti meg az adatot ha több sorváltás is van a sorok között.
Sajnos <p> és <br> elemeket is használ, így eléggé zavaros a működése.
Helyette Label komponenst használjunk, ezzel a html kóddal:
PageableListView
A működés hasonló a ListView-hoz, de ez a komponens lapozható, mivel egy PagingNavigator van hozzárendelve.
Java:
Az aktuális lap beállítása/átállítása (0-val indul):
Az aktuális lap számának lekérdezése (0-val indul):
(hasznos funkció ha egy másik WebPage-ről visszatérve, a lapozót is vissza akarjuk állítani)
Egy lapon megjelenő sorok számának beállítása/átállítása:
Lista beállítása/átállítása:
PageExpiredException
PageExpiredException keletkezhet akkor amikor lejár a session. Ekkor az oldal már nincs tárolva a page-map tárban,
így az exception kiváltódik.
Azonban előfordulhat az is, hogy a böngésző back gombja után, egy linkre kattintva az oldalon,
PageExpiredException keletkezik.
Ebben az esetben sincs meg az oldal a page-map tárban. Ilyenkor meg kell vizsgálni mi ennek az oka.
Általában ilyenkor
a lap tartalmaz olyan objektumokat melyek nem implementálják a Serializable interface-t,
és így a lap a page-map -ből kikerül amikor más oldalra
navigálunk. Megoldás: implementáljuk a Serializable interface-t azokban a saját osztályainkban melyeket a
lapok tárolnak (User, Init osztályok).
page mount
Ez arra szolgál hogy külső helyről be lehessen hívni az alkalmazásba nice url módon.
Ha a MyApplication.init()-be ezt írjuk:
akkor ezzel a nice url-lel hívhatjuk az alkalmazást:
ahol a MyPage osztály konstruktora kapja meg a vezérlést.
Természetesen paraméter is lehet az url-ben, és a MyPage osztály fogadhatja a PageParemeters-el.
Speciális mount, például:
Ebben az esetben a Lekerdez osztályhoz akkor is eljut a hívás ha a /lekerdez után / van,
és az URI tovább folytatódik, például:
De nem jut el a hívás a Lekerdez osztályhoz amikor nem / jellel folytatódik az URI, például:
Ez a speciális mount megjavítja azt a bug-ot is, amikor / jel van egy paraméteren belül!
Ha ilyen paraméter előfordul, akkor mindenképp ezt a mount-ot kell alkalmazni!
page parameters
A webpage konstruktor kapjon egy PageParameters argumentumot, ebből lehet kiszedni a paramétereket.
Ha egy webpage-nek van üres konstruktora és egy PageParameters-t fogadó konstruktora akkor a framework
az utóbbit hívja ha mindkettőt lehet.
Az alkalmazást egy külső linkről meghívva átadhatunk neki paramétereket a szokásos módon az url-ben:
BookmarkablePageLink esetén átadhatunk a hívottnak page paramétereket:
A lapok közötti adatátadásnál lehetséges hogy a hívó a hívott oldalt példányosítja, feltölti, és ezt átadja a
setResponsePage() metódusnak:
Panel
A Panel egy olyan összetett komponens melynek külön markup-ja és java osztálya van (extends Panel),
és egy másik lapra akár többször is beilleszthető. A java osztályán keresztül paraméterezhető,
így dinamikusan változhat a tartalma.
A Panel markup-ja a <wicket:panel> és <wicket:head> elemekkel valósítható meg.
A <wicket:panel> és </wicket:panel> közötti rész ami valójában bekerül a beillesztés helyére,
a rajta kívüli részek figyelmen
kívül maradnak.
A <wicket:head> és </wicket:head> közötti részek is bekerülnek a beillesztés helyére,
de a html <head> részébe.
Ez azért hasznos mert a panelhez is szükség lehet css-re, javascript-re.
Saját panel mintapélda:
Markup (MyPanel.html):
Java (MyPanel.java):
Saját panel beillesztése egy oldalra:
Markup:
Java:
PasswordTextField
Jelszó bekérő mező.
Nem törli ki a mezőből a tartalmat:
popup window
Egyes böngészők (pl. Firefox) egyre több memóriát foglalnak ablak nyitáskor-záráskor,
de pl. a Google Chrome jól működik.
Ennek nincs köze az Apache Wicket-hez, kipróbálható magában a böngészőben az ablak nyitás-zárás memória igénye.
A popup funkció csak a Link és az ExternalLink komponensekre (+ a leszármazottaikra) működik !
Egy ilyen komponensre kattintva akkor jelenik meg az eredmény új ablakban, ha a komponenshez PopupSettings van
hozzárendelve.
Java:
A popup ablakban lévő link például visszaadhat egy értéket a hívó lap egy mezőjébe,
az opener.document módszerével.
Java:
property expression
Egy adott objektum egy tagjának címzése:
Ponttal jelölt formát használhatunk egymásba ágyazott objektumok esetén.
Array vagy List esetén a propertyB indexként értelmeződik, és az Array vagy List egy elemét címzi.
Szögletes zárójeles formát használhatunk Array, List, vagy Map esetén.
Array vagy List esetén a propertyB indexként értelmeződik.
Map esetén a propertyB kulcsként értelmeződik. A kulcs bármilyen karaktert tartalmazhat, kivéve szögletes zárójelet, mert akkor nem működik az elérés!
A ponttal vagy szögletes zárójellel összefűzött tagok tetszőleges sokszor ismételhetők.
Az aposztrófnak és idézőjelnek nincs különleges jelentése, tehát ne használjuk, mert nem működik
(pontosabban a kulcs része lesz):
RadioChoice
Html radio gombsor megvalósítása:
egy kettő
Markup:
Az <input type="radio"> elemek elhagyhatók a markup-ból.
Java:
A model, a listaelemek, és a renderer pont úgy működik mint a DropDownChoice esetén.
Alapesetben a radiogombok egymás alatt vannak, mivel mindegyik után egy <br/> kerül, ez a suffix.
Ezen lehet változtatni, és egy metódusban megadni mi kerüljön az elemek után:
redirect
Redirect külső weblapra:
Redirect belső lapra:
resources
Egy resource-ra (css/image/js) lehetséges úgy hivatkozni, hogy a web-designer is jól lássa a html lapot,
és a program futása közben is jól látszódjon.
Java kód nélkül is beilleszthető egy resource az oldalba statikusan, lásd
<wicket:link>
Css -> image hivatkozás:
Ebben az esetben a css-ben konkrét url-lel kell lehivatkozni az image-t, ami így tehető meg például:
Az egyetlen hátrány hogy az url-ben az alkalmazás nevét is szerepeltetni kell, vagy relatív url-t lehet használni.
Egy wicket alkalmazásban lévő fájlok leírhatók resource-url-lel a következő módon:
ahol a 'packageNév.osztályNév' -hez viszonyítva lehet elérni a fájlokat.
Ezzel az url-lel azonban nem lehet minden fájlhoz hozzáférni, mert elérhetőségi szabályok vannak:
Sosem érhetők el a következő kiterjesztésű fájlok:
.java
.class
.properties
Egy .html kiterjesztésű fájl csak akkor érhető el, ha nincs vele azonos könyvtárban
lévű ugyanilyen nevű .java fájl.
Az egyéb kiterjesztésű fájlok elérhetők resource-url-lel: .txt .pdf .jpg .css .js .kutyafule ...
Forrás: WIA.250
Serializable
Az összes olyan osztálynak melyet a MySession-ben tárolunk, implementálnia kell a java.io.Serializable interface-t,
továbbá az osztály tagjainak is implementálnia kell a java.io.Serializable interface-t.
Ha ezt a szabályt nem tartjuk be
akkor a standard hibakimeneten szerializálásra vonatkozó exception-t kapunk. Ezt el kell hárítani,
különben nagyon furcsa
dolgokat tapasztalhatunk, pl. érthetetlen session expired.
Forrás: WIA.74
Session
A session létrehozására a MyApplication osztályban felül kell definiálni a newSession() mtódust:
A session lekérdezésére a MySession osztályban lévő get() metódus szolgál:
Így tehát a session-t a program tetszőleges helyéről elérhetjük a következő módon:
A session getId() metódusa nem használható rögtön a webalkalmazás első meghívásakor (még null-t tartalmaz),
ezért érdemes bevezetni a MySession-ben egy saját "myId" változót és egy saját getMyId() metódust.
A getMyId() visszaadja a saját myId tartalmát, de ha az még null akkor előtte belerak egy véletlen számot.
Az így kapott session-t sose tároljuk le változóba, mert később nem biztos hogy a változó jó
session-objektumra fog mutatni.
A böngészőben back-el visszakapott oldal (Serializált-ból visszaállított) változója nem az aktuális session-re
fog mutatni.
Model sose mutasson session-re. Ha session-be szeretnénk tárolni az adatokat akkor azt később,
például egy gombnyomásra tegyük be a session-be !
A régi módszer szerint a session-t (MySession)Session.get() alapján kaptuk meg, azonban ez mást
adhat vissza végrehajtási szálanként,
így különböző Session objektumot kapnánk (lásd: API-doc: Session)
SubmitLink
Ezzel a komponenssel képes egy html oldalon megjelenő link is submit-álni egy formot.
Ha egy SubmitLink a formon kívül van, akkor a konstruktorában meg kell adni azt a formot amit submit-álni kell.
A markup lehet link és gomb kinézetű is.
Markup:
Java:
Fontos hogy a submitálandó form-ra ne használjuk a setOutputMarkupId(false) beállítást, hiszan a SubmitLink
mögött álló javascriptnek
szüksége van arra, hogy a form-nak legyen "id" attribútuma. Ellenkező esetben a SubmitLink nem működik !
Nem lehet vele popup ablakot nyitni !
TabbedPanel
Ezzel a komponenssel az a probléma hogy nem lehet egy fület "disabled" állapotba tenni,
és a fülekre való kattintáskor lefutó eseményhez sem lehet hozzáférni
Forrás: WEX -> compref -> TabbedPanel
TextArea
Markup:
Java:
TextField
Markup:
Java:
validator
A validátorokhoz tartozó resource key-ek megtalálhatók az API doc-ban a validátor osztályoknál.
Ha a dokumentáció nem tartalmazza, akkor az osztály nevét kell használni, például: RangeValidator
Alaposztályok a validáláshoz, az org.apache.wicket.validation.validator package-ből:
StringValidator
MinimumValidator
MaximumValidator
RangeValidator (Date-re ne használjuk, mert nem lehet a minimum-maximum dátumot formázni a hibakiíráshoz).
DateValidator
! ne használjuk a NumberValidator osztályt, mert elavult !
Ha validátort keresünk, nézzük meg az IValidator interface-t, alatta láthatjuk az implementációkat.
Validátor példák. A komponens add() metódusával használandók:
A lehetséges properties bejegyzéseket leírják a validátor osztályok dokumentációjában, ezek a szokásosak:
Saját validátor mintapélda: WIA.192
WebMarkupContainer
Általános markup tag-hez hozzárendelhető pl: <p> vagy <div> így ezeket a html részeket
(és ami be van ágyazva) eltüntethetők,
vagy átállíthatók az attribútumuk például:
Markup:
Java:
<wicket:container>
Egy html egységet lehet vele összefogni, és például a megjelenését letiltani.
Akkor nagyon hasznos ha helyette nem lehet normál html tag-et használni, pl. egy <table> belsejében.
Markup 1. lehetőség:
Markup 2. lehetőség (nem wicket:container-rel, hanem tetszőleges html tag-gel):
Java:
<wicket:enclosure>
Egy html-elem és a közrezáró elem(ek) elrejtése egyszerre.
Ebben a példában látható, hogy ha a "kettoBelso" elemet elrejtjük egy setVisible(false) metódussal,
akkor az összes wicket:enclosure közé zárt elem is
láthatatlanná válik:
A "child" határozza meg hogy melyik belső elem az, melynek láthatósága vezérli az egész wicket:enclosure
láthatóságát. Ha több elem van egymásba ágyazva akkor a "child"-ben kettősponttal kell elválasztani az egymásba ágyazott
elemeket.
Forrás: WIA.159
<wicket:link>
Statikus link készítése java kód nélkül.
Másik lapra hivatkozás (ha pl. ugyanebben a könyvtárban van a másik lap):
De ennél jobb ha megadjuk az oldal teljes elérési útját mivel lehet hogy más könyvtárban vagyunk:
Image hivatkozás:
Nem használhatjuk így: "/res/wicket_book.jpg" !
Css hivatkozás:
Nem használhatjuk így: "/res/main.css" !
<wicket:remove>
A közötte lévő elemek teljesen eltávolításra kerülnek a végleges html lapról, a lap tervezésénél használjuk.