onclick felülírása setAttribute-tal
Egy oldalon lévő Eddig minden tökéletes. Ha visszaadnám neki a saját onclick-eseményétmódon, akkor a DOM-ba aminek tulajdonképpen semmit sem kéne számítania, máris máshogy dolgozza fel:
A poszt megírása közben sikerült megoldanom, de néhány okból mégis közzéteszem:
1. talán létezik ennél elegánsabb módszer,
2. hátha jól jön valakinek, aki belefut egy hasonló problémába,
3. az "object+semmi=function" egyenlet okára kíváncsi lennék.
Illetve, a leglényegesebb, hogy kinyerhető-e az eredeti onclick esemény a function(){...} belsejéből? (Kialertezve is a function()-nnel együtt dobta ki, de a substring()-et nem ette meg.)
A működő megoldás:Ennek eredménye pedig már
(A meghívott confirmLeaving() függvény – amennyiben a felhasználó az adott űrlapon módosított az eredeti értékeken – megkérdezi, hogy biztosan elnavigál-e az adott oldalról.)
■ <a>
elemek onclick-jét változtatnám utólag JavaScripttel (setAttribute), amivel nincs is gond – egészen addig, amíg nem szeretném valamilyen módon a már meglévő saját onclick-eseményeiket megtartani, kombinálva az újjal. Az eredmény több mint meglepő.
links = document.getElementsByTagName('a');
for (i = 0; i < links.length; i++) {
if (links[i].target != '_blank') {
links[i].setAttribute('onclick', 'uj();');
}
}
links[i].setAttribute('onclick', links[i].onclick);
<a ... onclick="[object]">
módon épül be, ami nem túl barátságos. És itt jön a több mint meglepő rész: ha már annyival megváltoztatom, hogy
links[i].setAttribute('onclick', links[i].onclick + '');
<a ... onclick="function onclick() { eredeti(); }">
az eredmény, csakhogy ettől még ugyanúgy nem csinál semmit. Tehát hozzá kell csapni az onclick() függvény meghívását az onclick esemény végéhez, hogy le is fusson. Bonyolódik? Még nem. Az általam hozzárendelni szándékozott onclick eseménynek ugyanis van egy true/false visszatérési értéke, ami máris izgalmasabbá teszi. Na meg persze az, hogy nem minden <a>
rendelkezik onclick-kel, lévén a többség csak egyszerű link.A poszt megírása közben sikerült megoldanom, de néhány okból mégis közzéteszem:
1. talán létezik ennél elegánsabb módszer,
2. hátha jól jön valakinek, aki belefut egy hasonló problémába,
3. az "object+semmi=function" egyenlet okára kíváncsi lennék.
Illetve, a leglényegesebb, hogy kinyerhető-e az eredeti onclick esemény a function(){...} belsejéből? (Kialertezve is a function()-nnel együtt dobta ki, de a substring()-et nem ette meg.)
A működő megoldás:
for (i = 0; i < links.length; i++) {
if (links[i].target != '_blank') {
if (links[i].onclick != null) {
links[i].setAttribute('onclick', links[i].onclick+'; if (!confirmLeaving()) { return false; }; onclick();');
}
else {
links[i].setAttribute('onclick', 'return confirmLeaving();');
}
}
}
<a ... onclick="return confirmLeaving();">
illetve <a ... onclick="function onclick() { eredeti(); }; if (!confirmLeaving()) { return false; }; onclick();">
lesz, ami pontosan az elvárt működést hozza.(A meghívott confirmLeaving() függvény – amennyiben a felhasználó az adott űrlapon módosított az eredeti értékeken – megkérdezi, hogy biztosan elnavigál-e az adott oldalról.)
NE!
onclick
eseményt akarsz megadni egy DOM elemre, akkor állítsd be azonclick
tulajdonságát, vagy használd a böngésző eseménykezelő csatoló függvényét (attachEvent / addEventListener). És ha máronclick
-et használsz, akkor ne stringet adj meg értéknek, hanem a függvényt magát add meg.Köszi, elegánsabb.
nehezebb
Világos
Viszont a setAttribute-tal ellentétben most az eredeti onclick-kel is rendelkező elemek esetében a confirm után dob egy "A várt elem objektum" hibát a debugger, méghozzá az új függvény által meghívott onclick()-re (aztán lefut). Gyanítom azért, mert ez foglalt kifejezés... Ezt el lehet kerülni valahogy?
Jól emlékeztem, hogy láttam
Egy kis értetlenkedés részemről: ez nem úgy van, hogy a DOM végeredményben egy objektum, aminek vannak attribútumai és metódusai? Valamikor régen azt olvastam, hogy egy objektum attribútumaihoz nem illik közvetlenül hozzáférni, helyette inkább getter/setter metódusokat kell használni.
Ahogy az előbb a sitepoint-on nézegettem a DOM leírását, nekem az jött le, hogy végeredményben pl. az onclick is egy attribútum a sok közül és ha hű akarok maradni az OOP szokásokhoz/elvárásokhoz, akkor a setAttribute metódus segítségével kell beállítanom, nem közvetlen értékadással.
Akkor most mégsem? Vagy hogy van ez?
nekem az jött le, hogy
Úgy van. Pontosabban addEventListener() (Explorerben 9 verzió előtt attachEvent()) metódus hívással kellene felvétetni a DOM node-dal az eseménykezelőit. Illetve az eltávolításuk removeEventListener() ((Explorerben 9 verzió előtt detachEvent()) metódus hívással kellene történjen.
Magyarán Poetronak abban
(bocs, kicsit figyelmetlen voltam szokásomhoz híven, csak addig olvastam, hogy "nem erre való" + az általa beírt példában a onclick=-ig)
Magyarán Poetronak abban
Régebben azzal szoktunk mentegetőzni, hogy a régi böngészők kedvéért használunk onclickes eseménykezelő beállítást, de manapság már a lustaság sem lehet kifogás, mert a JavaScript keretrendszerek elvégzik az addEventListener()/attachEvent() különbség kezelését. Személy szerint én az egyszerűsége és függetlensége miatt fórumra beírt kódban még mindig onclicket szoktam használni, de máskülönben már nem.
attribútum vs tulajdonság
setAttribute
a DOM elem attribútumát, míg másik a tulajdonságát állítja be. Az egyik megjelenik a DOM fában, a másik nem. És egy másik fontos dolog, hogy a DOM attribútum egy string, míg a tulajdonság bármilyen típust felvehet. Ezért is szerencsésebb tulajdonságként hozzárendelni az eseménykezelőket, mert akkor közvetlenül le tudja a böngésző futtatni a függvényt, nem kell előbbeval
-oznia a stringet (minden alkalommal), ráadásul az eseménykezelő is sokkal barátságosabban működik (és működik minden böngészőben), míg asetAttribute
esetében ez kevésbé megbízható.Hm... na ezt még gyakorolni
OOP könyvekben az utóbbit használják az osztály-/példányváltozókra, én meg szokás szerint összekevertem őket.
Szasztok!
Pontosan
és a formot letárolod
használj egy sima addEventListenert vagy ha csak egy eseménykezelőt állítasz a linkekre a sima DOM level 0 szintü megoldás is megteszi. és ott vizsgálódsz, onnan indítod a confirm ablakot is és ha az false értékkel tér vissza megállítod a link default működését, amit az event.preventDefault() függvényel tudsz megtenni. mindjárt mutatok egy példát
Igen, érzem, hogy biztosan
<!DOCTYPE html PUBLIC
Alakul (bonyolódik)
document.link
csak ahref
-et tartalmazó<a>
-kat gyűjti be, így maradnia kellett agetElementsByTagName('a')
-nak. Ezután két dolgot kellett megoldani: az eredetionclick
-et tartalmazó linkeket, illetve, hogy az IE nem fogadta el aze.returnValue = false;
-t – csak akkor, ha nemlink.onclick
-kel csináltam, hanem a Poetro által ajánlott addEventListener/attachEvent megoldásokkal. (Az rejtély, hogy ezek híján miért dob hibát a neki valóban ismeretlene.preventDefault
miatt, hiszen egyrészt ellenőrizve van, hogy létezik-e, másrészt eseménykezelők esetén nem zavartatja magát.)Az eredeti
onclick
-ek megtartására egy meglehetősen csúnya megoldást találtam ki: mielőtt felüldefiniálnám, megkapja az értékét alink.ondblclick
, majd megerősített oldalelhagyás után meghívomthis.ondblclick()
módon. Ez minden, csak nem elegáns – szebb utat viszont nem találtam arra, hogy "helyileg" tároljam a linkben. (A Te verziódból pedig ugye ki kellett vennem a preventDefault-os részt, hogy IE-vel is működjön, így maradt az egyszerűreturn false
.) Működőképesen így néz ki:onclick
-eket meghívjam, mert attachEvent-tel athis
a teljes dokumentumra fog hivatkozni. A Quirksmode-on ezt írják:Intenzívebben utánajárva az
event.srcElement
lesz a megoldás (ez talán még másnak is hasznos lehet a későbbiekben), tehát az elvileg professzionálisabb kód így fest:ondblclick
-be való átpasszolásnál miképp tehetném meg ezt elegánsabban (rakhatom persze pl. arel
-be, vagy egyedi attribútumba, de egyik sem az igazi). Köszönöm még egyszer a végigolvasást, és az időtök rászánását!(Apropó, annak van különösebb jelentősége, hogy
confirm()
helyettwindow.confirm()
-et írtál a kódba?)Javítom
Bocs de ezt én néztem be, mivel ilyen módon nagyon ritkán akasztok esemény kezelőket elemekre. A lényeg hogy kihagytam egy fontos sort ami a IE-hez kell ez pedig így néz ki kijavítva:
e
változó miatt kellet volna sipákolnia nem a preventDefault miatt.Ha a DOM újabb modellje szerint (attachEvent/addEventListener) akasztod rá a esemény kezelőket egy elemre a régebbi, azt hiszem a 8as verzióig az Explorer valóban rosszul definiálja a this értékét, ez a szabványban úgy működik hogy a this azt az elemt adja vissza amihez kapcsoltad a függvényt függetlenül attól hogy a e.target vagy e.srcElement mire mutat mert egy buborékban el is térhet a kettő értéke, ha mégis akarod a this-t használni akkor neked optimalizálni kel, erre Poetro-nak pl van egy kiindulási alapja, amihez szükséges a closure technika megértése amihez szintén Poetronak van egy cikke itt. A linkHandler függvényt most javítottam avval a sorral, így már működnie kell.
Nagy jelentősége sokszor nincs de ritkán előferdül, hogy meglepetés éri az embert a globális függvények használata során, ha pl. valamiért megváltozik a kód futási kontextusa, ez legtöbször az eval-al tud szörnyű lenni ez nálam már csak megszokás, hogy tutira megyek.