Avatar billede majbom Novice
26. maj 2008 - 21:48 Der er 67 kommentarer og
2 løsninger

kan ikke sætte onClick med DOM

hej experter

nu har jeg siddet i et par timer og søgt og prøvet alt muligt, men jeg kan bare ikke få noget så simpelt som nedenstående til at virke:

button = document.createElement("button");
button.appendChild(document.createTextNode("CLICK"));
document.getElementsByTagName('body')[0].appendChild(button);
button.setAttribute("onClick", "alert('hej')");

der sker intet når jeg trykker på knappen, jeg har prøvet onclick/onClick både med setAttribute og med button.onClick/click
jeg har prøvet at lave en funktion der ingen argumenter tog og så gøre det således:

button.setAttribute("onClick", testFunc);

ligeledes både med stort og lille 'c' og setAttribute og button.

jeg har lige tjekket w3schools.com (http://w3schools.com/htmldom/dom_obj_pushbutton.asp) og der synes jeg ikke at jeg kan finde noget. kan det virkelig passe at man ikke kan sætte onclick på en button vha. DOM?

på forhånd rigtig mange tak!
Avatar billede olebole Juniormester
26. maj 2008 - 21:59 #1
<ole>

Nøøøhhh ... w3schools.com er ikke mange døde fluer værd! Får man endelig navigeret sig udenom de værste fejl og misforståelser, kommer man til alle sitets mangler og udeladelser  :o|

Du kan ikke sætte en event handler med setAttribute metoden. I stedet skal du i IE anvende attachEvent og i resten af de DOM kompatible browsere addEventListener:
    http://msdn.microsoft.com/en-us/library/ms536343(VS.85).aspx
- og:
    http://developer.mozilla.org/en/docs/DOM:element.addEventListener

/mvh
</bole>
Avatar billede elskermad.dk Nybegynder
26. maj 2008 - 23:24 #2
olebole: jeg bruger tit fx at lave en object.onclick = func;
burde man i stedet bruge event-funktionerne som du beskriver?
Avatar billede elskermad.dk Nybegynder
26. maj 2008 - 23:24 #3
.. og undskyld jeg invaderer spørgsmålet ;o)
Avatar billede roenving Novice
26. maj 2008 - 23:42 #4
>>elskermad

-- ja, man bør bruge de rigtige funktioner og evt. have en bagdør, hvor du anvender den gammeldags metode:

if(element.addEventListener)
  element.addEventListener("click", func, true);
else if(element.attachEvent)
  element.attachEvent("onclick", func);
else
  element.onclick = func;
Avatar billede majbom Novice
27. maj 2008 - 09:09 #5
det virker jo fremragende, og hvis man kalder en funktion der tager et eller flere argumenter skriver jeg:

element.addEventListener("click", function(){func(args)}, true);

og det virker også som det skal. er det den korrekte måde at gøre det på?

-> ole - den måde du skriver det på lyder det som om at ie ikke understøtter DOM rigtigt, eller hvad?

jeg siger mange tak for løsningen, i må gerne smide et svar, både ole og roenving :)

-> elskermad.dk - det er helt i orden, du laver bare et spørgsmål med 30 point og så lægger jeg et svar :p
Avatar billede roenving Novice
27. maj 2008 - 14:13 #6
-- en wrapper til at lave det, kunne være:

function addEvent(elm, evnt, func){
  if(element.addEventListener)
    elm.addEventListener(evnt, func, true);
  else if(element.attachEvent)
    elm.attachEvent("on" + evnt, func);
  else
    elm["on" + evnt] = func;
}
Avatar billede majbom Novice
27. maj 2008 - 16:25 #7
en ide til hvorfor dette ikke virker:

addEvent(button, "click", function(){deleteProductType(json.types[i].type.id)});

når dette gør:

var typeId = json.types[i].type.id;
addEvent(button, "click", function(){deleteProductType(typeId)});

?
Avatar billede elskermad.dk Nybegynder
27. maj 2008 - 16:32 #8
den har problemer med argumenter når man gør det på den måde. man skal bruge noget preventDefault men jeg har aldrig rigtig forstået pricippet.
laver oftest mine ting således jeg kan undgå argumenter netop derfor
Avatar billede w13 Novice
27. maj 2008 - 16:34 #9
Kører du dette:

var typeId = json.types[i].type.id;
addEvent(button, "click", function(){deleteProductType(typeId)});

inde i en funktion? For så vil typeId jo blive deklareret lokalt og ikke globalt - derved kan du ikke bruge det i din anonyme function().
Avatar billede majbom Novice
27. maj 2008 - 16:42 #10
-> w13 - ja altså jeg har en funktion der får noget info fra en php-fil i json-"format" og denne json bliver gennemløbet og der bliver genereret en tabel med de data jeg får, i hver linje er der en knap, som bruges til at slette den pågældende linje fra databasen, det er den knap der skal køre funktionen deleteProduktType som logisk nok skal bruge id'et på den pågældende række...

det virker nogenlunde, bortset fra at alle knapperne sletter den sidste række i tabellen, så hver gang jeg laver en addEvent på button, gør den det på alle knapperne...
Avatar billede w13 Novice
27. maj 2008 - 17:57 #11
Så skal du vel bare overføre det rigtige element og ikke button?
Avatar billede majbom Novice
27. maj 2008 - 18:25 #12
-> w13 - jeg tror ikke du forstår... min kode ser således ud:

for (var i=0; i < json.types.length; i++) {

  row = document.createElement("tr");

  for(var j=0; j<json.types[i].type.values.length; j++){
      cell = document.createElement("td");
      cellText = document.createTextNode(json.types[i].type.values[j]);
      cell.appendChild(cellText);
      row.appendChild(cell);
  }

  cell = document.createElement("td");
  var typeId = json.types[i].type.id;
  addEvent(button, "click", function(){deleteProductType(typeId)});
  buttonText = document.createTextNode("Slet");
  button.appendChild(buttonText);
  cell.appendChild(button);
  row.appendChild(cell);

  style = Math.abs(style-1);
  row.setAttribute("className", "row"+style);
  tblBody.appendChild(row);
}
Avatar billede olebole Juniormester
27. maj 2008 - 18:30 #13
Det kræver rigtig god forståelse af mange principper at skrive god DOM-kode. Således risikerer man meget let at havne på dybt vand med crashende browsere flydende mellem bøjerne, når man bruger Ajax og event handlers.

Når man sætter anonyme funktioner som event handlers, får man meget ofte lavet cirkullære refrencer mellem JavaScript og DOM'en. Sker det, kan IE ikke frigive hukommelsen igen, når elementerne fjernes og null'es ... selv når der skiftes side, fejler IE ofte med at frigive hukommelsen!

Prøv f.eks. at åbne din Task Manger og load dette dokument i en IE. Læg mærke til, hvordan hukommelsesforbruget er drastisk stigende med hvert klik på knappen:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>TITLE</title>
</head>
<body>

<button onclick="bar()">TEST</button>

<div id="gnu"></div>

<script type="text/javascript">
var oPar = document.getElementById("gnu");
var oo = null;
function addEvent(oElm, sType, fn) {
    oElm.attachEvent("on"+sType, fn);
}
function foo(nInx) {
    var el = document.createElement("div");
    oPar.appendChild(el);
    el.appendChild( document.createTextNode("Div_" + nInx) );
    addEvent(el, "click", function() {alert("clicked")});
    addEvent(el, "mouseover", function() {alert("over")});
    addEvent(el, "mouseout", function() {alert("out")});
}
function bar() {
    var i, j;
    for (i=0; i<20; i++) {
      // Opret 500 elementer og indsæt dem i div'et 'gnu'
        for (j=0; j<500; j++) {
            foo(j);
        }
      // - og slet dem igen   
        while (oPar.firstChild) {
            oo = oPar.firstChild;
            oPar.removeChild(oo);
            oo = null;
        }
        oo = null;
    }
}
</script>

</body>
</html>
Avatar billede olebole Juniormester
27. maj 2008 - 18:33 #14
- og så må du i øvrigt aldrig tildele et element en event handler, før elementet er indsat i dokumentets DOM-træ. Ellers spilder IE taber også hukommelse  :o|
Avatar billede olebole Juniormester
27. maj 2008 - 18:34 #15
"Ellers taber IE også hukommelse" - skulle der stå  ;o)
Avatar billede olebole Juniormester
27. maj 2008 - 18:41 #16
Nu vil nogle nok indevende, at mit eksempel indsætter 10.000 elementer og derfor er urealistisk. Det er absolut ikke tilfældet.

Jeg kender f.eks. en bruger på Eksperten, der lavede en 'Eksperten-reader', som hele tiden stod og tjekkede visse af E's kategorier for nye spørgsmål/indlæg. På et tidspunkt, hvor vi tilfældig kom til at tale om emnet i en tråd, gik det pludseligt op for ham, hvorfor browseren med den pågældende applikation hele tiden crashede!  ;o)
Avatar billede majbom Novice
27. maj 2008 - 19:08 #17
-> ole - hold da op, den æder lige godt 120mb hver gang :0 - det er jo vildt!

okay, jeg var ikke klar over at man kunne tildele noget til et element efter det var blevet indsat i dokumentet, altså jeg troede at alt der skulle laves ifb et element skulle gøres inden man tilføjede det.
men så er det vel derfor at jeg har problemet med at alle button får tildelt den samme eventhandler, altså den sidste der bliver tildelt, bliver tildelt til alle knapperne?
Avatar billede majbom Novice
27. maj 2008 - 19:43 #18
så skal jeg tildele hver knap et id og derefter gennemløbe dem for at tilføje eventhandlers?

det er da lidt molboarbejde, eller er det bare mig
Avatar billede olebole Juniormester
27. maj 2008 - 20:59 #19
Jeg forstår ikke, hvad 'button' refererer til i kommentaren (27/05-2008 18:25:53). Jeg kan ikke se, du opretter en reference til noget. Jeg kan kun se, du lige pludselig prøver at tildele 'button' en event handler og noget tekstindhold ... men hvad er 'button', og hvor kommer den fra?
Avatar billede olebole Juniormester
27. maj 2008 - 21:01 #20
- og ja, man kan ofte komme ud for, at man må oprette en hel del elementer for derefter at loope over dem igen og tildele handlers  :o|
Avatar billede majbom Novice
27. maj 2008 - 21:10 #21
nej jeg kan godt se at der mangler noget kode dér...

det ser sådan her ud:

button = document.createElement("button");
var typeId = json.types[i].type.id;
buttonText = document.createTextNode("Slet");
button.appendChild(buttonText);
cell.appendChild(button);
addEvent(button, "click", function(){deleteProductType(typeId)});
row.appendChild(cell);

og dette står inde i en for løkke som løber min json-streng igennem

okay, det er ikke mig der har fået det forkert ind, det vil være rigtigt nok at generere en tabel med knapper i en for-løkke, for samtidig at tildele knapperne id'er og så derefter løber knapperne igennem og tildele eventhandlers til dem en efter en?
Avatar billede olebole Juniormester
27. maj 2008 - 21:20 #22
Såvidt, jeg umiddelbart kan se, har du problemer med i'et og den anonyme funktion
Avatar billede majbom Novice
27. maj 2008 - 21:24 #23
hvad mener du med problemer? det undrer mig at jeg ikke kan skrive json.types[i].type.id i deleteProduktType-kaldet, men at jeg er nødt til at smide den over i en variabel og så bruge den i kaldet.

men "anonym" funktion, går jeg ud fra at du mener:

function(){deleteProductType(typeId)}

?
Avatar billede majbom Novice
28. maj 2008 - 14:02 #24
nu har jeg lavet det sådan at der bliver tildelt et id til hver knap, for derefter at løbe knapperne igennem og tildele dem eventhandlers:

for(i=0; i<json.types.length; i++){
  btn = document.getElementById("btn_"+i);
  var typeId = json.types[i].type.id;
  addEvent(btn, "click", function(){deleteProductType(typeId)});
  btn=null;
}

men problemet er stadig det samme, den tildeler eventhandlers til alle de forgående knapper, så alle knapperne kalder funktionen deleteProductType med samme id som argument...
Avatar billede majbom Novice
29. maj 2008 - 06:59 #25
nu har jeg også prøvet med:

var btn = new Array();
for(i=0; i<json.types.length; i++){
  btn[i] = document.getElementById("btn_"+i);
  var typeId = json.types[i].type.id;
  addEvent(btn[i], "click", function(){deleteProductType(typeId)});
  //btn=null;
}

og det er stadig det samme... det kan da ikke passe at det ikke kan lade sig gøre :s
Avatar billede majbom Novice
29. maj 2008 - 16:59 #26
hvad så ole, har du givet op? :)

der er ikke en metode hvor man kan tjekke hvilket element der sender eventen, så man på den måde kan gøre det unikt fra række til række?
Avatar billede w13 Novice
29. maj 2008 - 19:47 #27
Nu har jeg ikke gennemlæst spørgsmålet så grundigt, men kan du ikke bruge new Function("blabla"+var+"blabla") i stedet for function(){blabla} til at sammensætte en funktion med i stringform?
Avatar billede majbom Novice
29. maj 2008 - 20:02 #28
-> w13 - jeg er ikke lige med, jeg kan lige prøve at ridse problemet op:

jeg genererer en tabel, med data fra database, og på hver linje skal der være en knap der kalder en funktion som sletter den pågældende række i db'en, denne funktion skal natruligvis have et id med som argument. når jeg tilføjer eventhandlers til knapperne, gør den det hele tiden til alle de forgående knapper, så når den er færdig, vil den sidste linje blive slettet uanset hvilken knap du trykker på...
Avatar billede majbom Novice
29. maj 2008 - 20:52 #29
jeg har prøvet at kode det lidt ned, det kan ses her:

http://majbom.com/testarea/DOM/dom4.htm

endnu en ting der undrer mig, som jeg ligger mærke til nu, er at den add'er en event igen efter den sidste knap er tilføjet, for den skulle alert'e "hej: "+i - hvor i er samme tal som den knap man trykker på, og da det ikke virker korrekt, ville jeg mene at alle knapper skulle alert'e "hej: 4", da den sidste knap hedder btn_4, men de alert'er "hej: 5".. ?

jeg bliver mere og mere forvirret...
Avatar billede olebole Juniormester
29. maj 2008 - 23:47 #30
Nej, jeg har ikke givet op, men har haft travlt med andre ting  =)

Når du gennemløber løkken, bliver værdien af 'i' forhøjet med én for hvert gennemløb. Når den anonyme funktion kaldes, anvender denne den værdi, som variablen 'i' har på det pågældende tidspunkt ... ikke værdien af 'i' på det tidspunkt, hvor event handleren sættes.

Hvis du opbygger koden proceduralt, kan du f.eks. gøre sådan:

        <script type="text/javascript">
            function addEvent(elm, evt, func){
                if(elm.addEventListener){
                    elm.addEventListener(evt, func, true);
                }else if(elm.attachEvent){
                    elm.attachEvent("on"+evt, func);
                }else{
                    elm["on"+evt] = func;
                }
            }
           
            function findTag(oSrcElm, sTag) {
                var oBody = document.getElementsByTagName("body")[0];
                while (oSrcElm!=oBody) {
                    if (oSrcElm.nodeName.toLowerCase()==sTag) return oSrcElm;
                    oSrcElm = oSrcElm.parentNode;
                }
                return null;
            }
           
            function foo(e) {
                var e = e ? e : event;
                var oSrcElm = e.target ? e.target : event.srcElement;
                oSrcElm = findTag(oSrcElm, "button");
                alert(oSrcElm.getAttribute("elmInx"));
            }
           
            function doDom(){
                body = document.getElementsByTagName('body')[0];
                for (var i=0; i < 5; i++) {
                    var btn = document.createElement('button');
                    btn.appendChild(document.createTextNode('btn_'+i));
                    body.appendChild(btn);
                    btn.setAttribute("elmInx", i);
                    addEvent(btn, "click", foo);
                    btn = null;
                }
            }
        </script>

Årsagen til 'findTag' er, at brugeren kunne klikke på et nested element. Event objektets target eller srcElement ville i så være det nestede element - ikke det element, handleren er sat på.

Personligt ville jeg nok opbygge det objekt orienteret, men det gør absolut ikke problemerne omkring IE's hukommelsestab mindre!
Avatar billede olebole Juniormester
30. maj 2008 - 00:22 #31
Har du brug for at tilknytte en værdi fra det øjeblik, handleren sættes, kan du sætte den som attribut på elementet.

Dog er det bedre kodestil at oprette et abstrakt element og sætte værdier som properties på dét - og så udelukkende bruge HTML elementet som interface. I andre programmerings miljøer er det et must at opbygge alt som abstraktioner, så applikationen/logikken er komplet adskilt fra 'display' og 'håndtag'.

Funktionalitet på WWW kom humpende ind fra venstre i Netscape 2.0 browseren - og blev klistret ovenpå et paragraf- og tabelværk, beregnet til opstilling og syndikering af videnskabelige måledata (HTML). Derfra har teknologien i rekordtempo udviklet sig bl.a. til et udviklingsmiljø, hvor man kan bygge store, komplekse business løsninger.

Af hensyn til bagudkompatibilitet halter både sprogene og browserne, der skal afvikle applikationerne, voldsomt bagud i forhold til ønskerne omkring udviklingen.
Samtidig er indlæringskurven for webteknologierne ganske lav. Det gør, at rigtig mange af de kodere, der skriver websites og -applikationer, ikke har nogen teoretisk uddannelse i programmering. En situation, der yderligere sinker udviklingen og 'opstramningen' af sprogene.

Både www's unge alder og dets historie/kultur gør således, at vi har en masse møllesten at slæbe på. Selvom webprogrammering er yderst let at gå til, er det - når tingene bliver komplekse - ofte vanskeligere at have med at gøre end mere 'langhårede' miljøer/sprog/teknologier. Forholdene bliver forhåbentligt bedre med tiden  ;o)
Avatar billede roenving Novice
30. maj 2008 - 00:51 #32
*lol*

>>ole

-- er det dig eller mig, der har en fotografisk hukommelse, for den der addEvent ser godt nok ens ud (bortset fra et 'n' i evnt, og jeg har den i hvert fald ud fra en tidligere gennemgang af problematikken !-)
Avatar billede majbom Novice
30. maj 2008 - 08:22 #33
hej ole, det er helt i orden, det var osse bare for sjov :)

så det vil sige at på en måde kan man sige at der hele tiden står "i" i den tildelte eventhandler, og så når den bliver kaldt, finder den ud af hvad værdien af "i" er? så giver det mere mening jo.

jeg vil også gerne opbygge det objekt orienteret, men det rækker min viden desværre ikke til på nuværende tidspunkt :( - så jeg starter med at prøve dit eksempel.

jeg har ikke, som sådan, brug for at vide hvilket element der sender eventen, det var bare hvis det var en bedre løsning (eller den eneste) - jeg forstår ikke helt det med det abstrakte du snakker om :S

og tak for en lille historie om www :)

-> roenving - det er "din" kode han bruger i eksemplet, jeg går ud fra at han har c/p fra mit link 29/5-20:52 - det er bare mig der har ændret lidt på det du kom med tidligere :)
Avatar billede majbom Novice
30. maj 2008 - 08:52 #34
fandme lækkert ole, din kode virker i mit lille testmiljø :)

nu skal jeg bare have den prøvet der hvor problemet egentlig ligger.

funktionen "foo", går den ikke ind og ser på hvilket element der har sendt eventen?

en anden ting; setAttribute "ElmInx" - er det en attribut du selv har fundet på? har aldrig set den før... kan man godt lave "sine egne" attributer?
Avatar billede olebole Juniormester
02. juni 2008 - 01:02 #35
roenving >> Som du måske husker, indeholder min mail-signatur følgende linjer:

--------------------------------------------------------------------------------------------
Everyone has a photographic memory .... some just don't have film

Hehe ... næhhh, det var såmænd helt som splazz skriver: copy/paste  ;o)

splazz >> "funktionen "foo", går den ikke ind og ser på" - jo.

- og det er helt legalt at bruge custom attributter, når de sættes/læses af script. Derimod giver det ingen mening at sætte f.eks. target attributten under html 4.01 Strict med det formål at få browseren til at åbne et nyt vindue (HTML 4.01 Strict indeholder som bekendt ikke target attributten)
Avatar billede majbom Novice
02. juni 2008 - 09:44 #36
-> ole - så var det egentlig også "foo"'s funktion jeg spurgte efter, da jeg spurgte om man ikke kunne se fra hvilket element eventen blev sendt.

det er da meget smart med custom-attributer :)

mht. "foo", så kan jeg ikke se hvorfor den kalder "findTag", umiddelbart virker det lige så godt bare at undlade linjen:

oSrcElm = findTag(oSrcElm, "button");

men der er sikkert en mening med galskaben :)
Avatar billede mclemens Nybegynder
02. juni 2008 - 10:15 #37
Jeg har været ude i et lignende problem med
"i" og jeg endte op med en eval som her:

... Hvilket der performer bedst ved test
af system ressourcer har jeg ikke testet.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>

   
        <meta http-equiv="Content-type" content="text/html; charset=ISO-8859-1"><title>dom4.htm</title>
       
        <script type="text/javascript">
            function addEvent(elm, evt, func){
  if(elm.addEventListener)elm.addEventListener(evt, function(){eval(func)}, false);
  else if(elm.attachEvent)elm.attachEvent("on"+evt, function(){eval(func)});
  else elm["on"+evt] = eval(func);
            }
   
            function doDom(){
                body = document.getElementsByTagName('body')[0];
                for (var i=0; i < 5; i++) {
                    var btn = document.createElement('button');
                    btn.appendChild(document.createTextNode('btn_'+i));
                    body.appendChild(btn);
                    addEvent(btn, "click", "alert('hej: "+i+"');");
                    btn = null;
                }
            }
        </script></head><body id="myBody" onload="doDom();">
</body></html>
Avatar billede majbom Novice
02. juni 2008 - 10:30 #38
-> mclemens - okay, det ser lidt mindre avanceret ud, det vil jeg lige teste...
Avatar billede majbom Novice
02. juni 2008 - 10:40 #39
-> mclemens - det kan jeg ikke få til at virke, jeg får "Typeuoverensstemmelse" fejl i linjen:

elm.attachEvent("on"+evt, func);

i funktionen "addEvent()"
Avatar billede mclemens Nybegynder
02. juni 2008 - 11:18 #40
elm.attachEvent("on"+evt, func); står ikke i 10:15:07 ;)
copy 'n' paste virker fint her, men man får så en eval. :-/

(men kig på systemressourcer hvad der performer
bedst i dit rigtige miljø ved klik på knappen...)
Avatar billede majbom Novice
02. juni 2008 - 11:29 #41
-> mclemens - nej det står der ikke, men den står i min funktion "addEvent" som bliver kaldt i dit eksempel :)
Avatar billede mclemens Nybegynder
02. juni 2008 - 11:55 #42
Den rettede funktion addEvent står i 02/06-2008 10:15:07
Avatar billede majbom Novice
02. juni 2008 - 11:59 #43
-> mclemens - DOH, det havde jeg sq overset, sorry :s
jeg leger lidt med det igen så :)
Avatar billede majbom Novice
02. juni 2008 - 13:14 #44
ja det hjalp lidt på det :)

så kan jeg også bruge:

document.location.href i onclick'en :)
Avatar billede mclemens Nybegynder
02. juni 2008 - 14:05 #45
Det er et stykke tid siden(lille år) jeg rodede med
den eval under add/attachevent og kunne ikke selv
huske hvorfor jeg egentlig endte op med den ...
(http://www.eksperten.dk/spm/833495)

- Dit spørgsmål her minder mig om det.
Jeg bryder mig ikke selv om at bruge eval
for meget (overdrevet), men når jeg kigger
på foo, findtag og det ekstra holder attribut
tror jeg, at jeg beholder den lille eval, det
er jo ikke en stor streng eller kompliceret
sammensætning af funktioner jeg eval'er...
Avatar billede majbom Novice
02. juni 2008 - 14:15 #46
okay, jamen det lader jo også til at virke efter hensigten :)

jeg lader den lige ligge til ole har været forbi, jeg er sikker på at han har en kommentar til den, hvad enten det er godt eller skidt :)
Avatar billede mclemens Nybegynder
02. juni 2008 - 14:54 #47
Det er skidt ;)
Avatar billede olebole Juniormester
02. juni 2008 - 22:36 #48
Jeg ville nok ikke bruge eval, men jeg tør ikke lægge hovedet på blokken i forhold til den faktiske forskel i performance ved denne specifikke problematik. Jeg har dog en klar formodning  ;o)

Linjen:
  oSrcElm = findTag(oSrcElm, "button");

- er medtaget af generelle grunde. Det betyder ikke så meget ved et button element. Forestil dig, du i stedet for en knap lavede denne konstruktion:
    <div>Noget tekst og noget <b>fed tekst</b>, der kan klikkes på</div>

- og satte en onclick handler på divet, som kører funktionen foo. Så kunne du indføre et par alerts i foo:

            function foo(e) {
                var e = e ? e : event;
                var oSrcElm = e.target ? e.target : event.srcElement;
                alert(oSrcElm.nodeName); // <-- Her ...
                oSrcElm = findTag(oSrcElm, "div");
                alert(oSrcElm.nodeName); // <-- og her
                alert(oSrcElm.getAttribute("elmInx"));
            }

Hvis du så klikker på den fede tekst, vil den første alert returnere 'B' og den anden 'DIV'. Klikker du derimod udenfor den fede tekst, vil begge alerts returnere 'DIV'. Derfor ...  =)
Avatar billede olebole Juniormester
02. juni 2008 - 22:40 #49
- funktionen finder altså det første, omkransende element, som har det søgte nodeName - dersom det var et child element, som udløste event'en
Avatar billede olebole Juniormester
02. juni 2008 - 22:41 #50
- og den kan derfor ikke bruges på konstruktioner à la:
    <span>Noget tekst og noget <span>andet tekst</span>, der kan klikkes på</span>
Avatar billede mclemens Nybegynder
02. juni 2008 - 23:09 #51
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head><meta http-equiv="Content-type" content="text/html; charset=ISO-8859-1"><title>dom4.htm</title>
 
        <script type="text/javascript">

            function addEvent(elm, evt, func){
  if(elm.addEventListener)elm.addEventListener(evt, function(){eval(func)}, false);
  else if(elm.attachEvent)elm.attachEvent("on"+evt, function(){eval(func)});
  else elm["on"+evt] = eval(func);
            }
 
            function doDom(){
                body = document.getElementsByTagName('body')[0];
                for (var i=0; i < 5; i++) {
                    var btn = document.createElement('div');
                    btn.appendChild(document.createTextNode('Noget tekst og noget '));
                    var btn2 = document.createElement('b');
                    btn2.appendChild(document.createTextNode('fed tekst '+i));
                    btn.appendChild(btn2);
                    btn.appendChild(document.createTextNode(', der kan klikkes på'));
                    body.appendChild(btn);
                    addEvent(btn, "click", "alert('hej: "+i+"');");
                    btn = btn2 = null;
                }
            }

        </script></head><body id="myBody" onload="doDom();">
</body></html>


vs.:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>

 
        <meta http-equiv="Content-type" content="text/html; charset=ISO-8859-1"><title>dom4.htm</title>
     
        <script type="text/javascript">

            function addEvent(elm, evt, func){
                if(elm.addEventListener){
                    elm.addEventListener(evt, func, true);
                }else if(elm.attachEvent){
                    elm.attachEvent("on"+evt, func);
                }else{
                    elm["on"+evt] = func;
                }
            }
         
            function findTag(oSrcElm, sTag) {
                var oBody = document.getElementsByTagName("body")[0];
                while (oSrcElm!=oBody) {
                    if (oSrcElm.nodeName.toLowerCase()==sTag) return oSrcElm;
                    oSrcElm = oSrcElm.parentNode;
                }
                return null;
            }
         
            function foo(e) {
              var e = e ? e : event;
                var oSrcElm = e.target ? e.target : event.srcElement;
                oSrcElm = findTag(oSrcElm, "div");
                alert('hej' +oSrcElm.getAttribute("elmInx"));
            }
         
            function doDom(){
                body = document.getElementsByTagName('body')[0];
              for (var i=0; i < 5; i++) {

                var btn = document.createElement('div');
                    btn.appendChild(document.createTextNode('Noget tekst og noget '));
                    var btn2 = document.createElement('b');
                    btn2.appendChild(document.createTextNode('fed tekst '+i));
                    btn.appendChild(btn2);
                    btn.appendChild(document.createTextNode(', der kan klikkes på'));

                    body.appendChild(btn);

                    btn.setAttribute("elmInx", i);
                    addEvent(btn, "click", foo);
                    btn = btn2 = null;
              }
            }

        </script></head><body id="myBody" onload="doDom();">
</body></html>
Avatar billede mclemens Nybegynder
02. juni 2008 - 23:14 #52
Umiddelbart ser det nogenlunde ens ud når
jeg måler system ressourcer (ctrl alt del).
Tester ved click på den fede tekst.

Under FF vinder den uden eval lidt over den med eval.
Mens i IE vinder den med eval lidt over den uden eval.
Avatar billede mclemens Nybegynder
02. juni 2008 - 23:21 #53
( P.s.: Den med eval kan godt bruges på <span>Noget tekst
og noget <span>andet tekst</span>, der kan klikkes på</span> )
Avatar billede majbom Novice
03. juni 2008 - 20:40 #54
ffs jeg hader når den ikke gemmer min kommentar!

nå, jeg prøver igen:

det ser ud til at begge løsninger har hver deres fordele og ulemper, så jeg tror jeg prøver mig frem, og finder ud af hvilken jeg skal bruge til mit projekt, det kan jo være jeg får brug for dem begge.

smid et svar ole og mclemens, så kan i dele :)
Avatar billede mclemens Nybegynder
03. juni 2008 - 21:45 #55
Her er det ene :o)
Avatar billede olebole Juniormester
04. juni 2008 - 15:31 #56
- og det andet  =)
Avatar billede majbom Novice
04. juni 2008 - 19:20 #57
mange tak for hjælpen venner :)
Avatar billede mclemens Nybegynder
04. juni 2008 - 19:21 #58
Velbekom, og tak for point :)
Avatar billede majbom Novice
04. juni 2008 - 19:25 #59
damn du er quick ;o)
Avatar billede olebole Juniormester
04. juni 2008 - 19:29 #60
Tak for points  =)
Avatar billede mclemens Nybegynder
24. juli 2008 - 23:10 #61
Avatar billede olebole Juniormester
26. juli 2008 - 15:22 #62
mclemens >> Jeg må desværre dømme din 'event handler ting' som værende dårlig og rystende overflødig. F.eks. kan der kun medsendes strenge som variabler - og det er i hvertfald for mig komplet ubrugeligt.

Medsender jeg et array som ["et", "to"], ender jeg øjensynligt op med strengen "et, to".
Medsender jeg objektet {"one":"en", "two":"to"}, ender jeg op med et tomt objekt.
Desuden skal enkelte apostroffer i strenge escapes med to backslashes: "blabla \\'noget i gåseøjne\\' blabla bla" - hvilket også er noget rod.

I forbindelse med mere avanceret kode - ikke mindst OOP - er løsningen komplet håbløs, da der ikke kan medsendes referencer og der ikke kan scopes!

Jeg forstår ikke begrundelsen for dine snørklede veje for at konstruere en måde at sætte event handlers på, men udfra teksten i din artikel at dømme, må det skyldes manglende forståelse for JS - og måske scoping i JS.

Det giver som bekendt ikke mening at diskutere koden i en artikel i kommenrafelterne under artiklen - og jeg har forlængst opgivet at arbejde seriøst med E's forfatter interface til artiklerne - men jeg vil prøve at strikke en artikel sammen om emnet på www.dengodekode.dk. Jeg har pokkers travlt lige for tiden, så det varer nok et par uger  =)
Avatar billede mclemens Nybegynder
26. juli 2008 - 16:28 #63
Umiddelbart kan jeg godt sende et array eller object...
- Men grunden til jeg skrev mit oprindelige om var egentlig
at jeg manglede en måde at fjerne funktioner fra event'en.

Grunden til at jeg ikke bruger foo og findtag er at IE,
som du selv er inde på, ikke refererer over til this på
samme måde som FF gør. Det gør så at man skal fange elementet
for at få adgang til et obj med gemte variabler eller evt.
en variabel der henviser til et globalt object ...

- det er ikke altid et fast element tag der skal søges efter
i findtag, og det kan være svært at vide om man rammer den rigtige
div med flere div's i hinanden.

Jeg er enig i dig i at det ikke er optimalt - jeg plejer nu kun
at bruge det jeg brugte før til at rette op på "this" problemet. Det
vil være rart hvis du finder en smutvej der gør det muligt uden eval
(jeg synes ikke rigtig at jeg kunne finde andet end det du foreslog i
29/05-2008 23:47:14)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><meta http-equiv="content-type" content="text/html; charset=iso-8859-1"><title>Eval compatible add-remove wrapper</title>

<script type="text/javascript">
evtlst={"id":0};

function ael(elm,evt,f){var i,j;
  if(elm.nodeType!=undefined){
    if(i=elm.getAttribute("evtlst")){
      if(evtlst[i][evt])evtlst[i][evt]+=f;
      else j=evtlst[i][evt]=f;
    }else{j="elm"+evtlst.id++;
      elm.setAttribute("evtlst",j);
      evtlst[j]={};evtlst[j][evt]=f;
    }
    f=evtlst[i?i:j]["f"+evt]=function(){eval(evtlst[i?i:j][evt]);};
  }if(!i||j){
    if(elm.addEventListener)elm.addEventListener(evt,f,false);
    else if(elm.attachEvent)elm.attachEvent("on"+evt,f);
    else elm["on"+evt]=f;
  }
}

function rel(elm,evt,f){var i;
  if(elm.nodeType!=undefined){
    if(i=elm.getAttribute("evtlst")){
      if(evtlst[i][evt]){
        evtlst[i][evt]=evtlst[i][evt].replace(f,"");
        if(evtlst[i][evt]!="")evtlst[i]["f"+evt]=function(){eval(evtlst[i][evt]);};
        else{
          evtlst[i][evt]=null;init=true;f=evtlst[i][evt];
          elm.removeAttribute("evtlst");
        }
      }
    }
  }if(!i){
    if(elm.removeEventListener)elm.removeEventListener(evt,f,false);
    else if(elm.detachEvent)elm.detachEvent("on"+evt,f);
    else if(typeof elm["on"+evt]=="function")elm["on"+evt]=null;
  }
}

ael(window,"load",addalerts);

function addalerts(){
  element=document.getElementById("testelement");
  ael(element, "click", "test={'one':'en', 'two':'to'};alert('lokaltest: '+test['one']);forward(test);");
  ael(element, "click", "test=['et', 'to'];alert('lokaltest: '+test[0]);forward2(test);");
}

function forward2(arr){
  for(i=0;i<arr.length;i++)alert(i+": "+arr[i]);
}

function forward(obj){
  for(i in obj)alert(i+": "+obj[i]);
}
</script>

</head><body>
<div id="testelement">This is the test element</div>
</body></html>
Avatar billede mclemens Nybegynder
26. juli 2008 - 16:49 #64
Hmm, du mener nok et array eller obj der er defineret i
forvejen ... den eneste måde jeg lige kan se det på er:

var tmp;

function addalerts(){
  tmp={'one':'en', 'two':'to'};
  element=document.getElementById("testelement");
  ael(element, "click", "forward(tmp);");
}

function forward(obj){
  for(i in obj)alert(i+": "+obj[i]);
}

(men det er jo heller ikke optimalt, der kan dog også
sættes en attribut på elementet og så have et globalt obj
istedet og så læse i funktionen efter attributen og hente
objectet fra det globale object ... men igen lidt snørklet)

- Hvordan sender du dit array eller obj
med via en almindelig addeventlistener?
Avatar billede olebole Juniormester
26. juli 2008 - 17:41 #65
Nej, jeg mener ikke et globalt defineret objekt (og det går jeg udfra, du mener i dit eksempel, selvom du erklærer variablen med 'var') - men et objekt, der er lokalt defineret i en funktions scope og ønskes medsendt til handleren ved en event.

Det er der være flere måder at gøre på, men det kunne f.eks. være sådan:
    var a = ["et", "to"];
    oObject.addEventListener("click", function(){myFunc(a)}, false);

Løsningen kan under ingen omstændigheder bruges, hvis arrays og objects skal være globale for at virke. Det (og en del andet) gør den komplet ubrugelig i forbindelse med OOP.

Du kan ikke få FF til at overholde standarden omkring this, men hvis man gør det korrekt, er der heller ingen problemer i dén retning. Det handler om scopes, men det er for lang en omgang at kaste sig ud i her, så du må vente på artiklen  =)

Desuden kører du en bunke kode, hvergang du kalder funktionen. Alle dine if-sætninger skal således evalueres ved hvert kald af funktionen - og det er jo vildt overkill. If-sætningerne bør vel kun køres én gang - så der tages højde for broweren én gang for alle i dét dokument  ;o)
Avatar billede mclemens Nybegynder
26. juli 2008 - 18:40 #66
Jeg ser frem til artiklen, når du skriver den vil det
være rart hvis du lige kom forbi removeeventlistener også
- (jeg synes at jeg har problemer med at
fjerne den anonyme funktion i ovenstående)

...

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><meta http-equiv="content-type" content="text/html; charset=iso-8859-1"><title>Basic event add-remove wrapper</title>

<script type="text/javascript">
function ael(elm,evt,f){
  if(elm.addEventListener)elm.addEventListener(evt, f, false);
  else if(elm.attachEvent)elm.attachEvent("on"+evt, f);
}

ael(window,"load",addalerts);

function addalerts(){
    var a = ["et", "to"];
  oObject=document.getElementById("testelement");
    oObject.addEventListener("click", function(){myFunc(a)}, false);
    oObject.removeEventListener("click", function(){myFunc(a)}, false);

  oObject=document.getElementById("testelement2");
    oObject.addEventListener("click", myFunc2, false);
    oObject.removeEventListener("click", myFunc2, false);
}

function myFunc(a){
  alert(a.length);
}

function myFunc2(){
  alert(1);
}
</script>

</head><body>
<div id="testelement">This is the test element.</div>
<div id="testelement2">This is the test element.</div>
</body></html>
Avatar billede olebole Juniormester
26. juli 2008 - 19:40 #67
Du kan ikke fjerne den anonyme funktion i min sensts kommentar - det vil kræve en registrering af handleren ... det ligger i den kommende artikel  =)

I øvrigt burde du se på funktions metoden apply, der er en vigtig metode at kende, når det kommer til scoping - specielt i forbindelse med OOP:
    http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Function:apply

- men den kommer også med i artiklen
Avatar billede mclemens Nybegynder
27. juli 2008 - 18:15 #68
Lyder lidt interessant med den apply, søgte lidt og faldte over denne:
http://www.quirksmode.org/blog/archives/2005/08/addevent_consid.html
- Tror jeg vil kigge lidt i kommentarer derinde på et tidspunkt ...
Avatar billede olebole Juniormester
27. juli 2008 - 21:42 #69
Den vil jeg også kikke igennem på et tidspunkt  ;o)

Du skal iøvrigt lige vide, at de værste problemer omkring IE's memory leaks ser ud til at være løst. Det er efterhånden et stykke tid siden, MS udgav en sikkerhedsopdatering, som tager hånd om dette problem. De har formodentlig været hårdt presset Ajax' hastige udbredelse  ;o)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi tilbyder markedets bedste kurser inden for webudvikling

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester