Robert Kabinger: JavaScript Functionsreferenz bei onclick funktioniert nicht

  
<?xml version="1.0" encoding="iso-8859-15" ?>  
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml">  
   <head>  
      <title>JavaScript Functionsreferenz bei onclick funktioniert nicht</title>  
      <style type="text/css">  

  
         div.box  
         {  
            display: block;  
         }  
         div.box_invis  
         {  
            display: none;  
         }  

  
      </style>  
      <script type="text/javascript">  

  
         function start()  
         {  
            for (var i = 0; i < 3; i++)  
            {  
               var box = document.getElementById("box");  
               var a = document.createElement("a");  
               a.href = "#box_" + i;  
               a.onclick = function () { showbox(i); };  
               a.appendChild(document.createTextNode("showbox(" + i + ")"));  
  
               box.appendChild(a);  
            }  
         }  
  
         function showbox(nr)  
         {  
            var box = document.getElementById("box_" + nr);  
            box.className = "box";  
         }  

  
      </script>  
   </head>  
   <body onload="start()">  
      <div class="box" id="box" />  
      <div class="box_invis" id="box_0">0</div>  
      <div class="box_invis" id="box_1">3</div>  
      <div class="box_invis" id="box_2">2</div>  
   </body>  
</html>  

Kann mir bitte irgendjemand sagen warum das nicht funktioniert?
Das JavaScript soll einfach nur beim Klick auf einen der generierten Links die Funktion (showbox) ausführen, welche die Klasse eines <div>'s ändert.

--
ie:% fl:| br:^ va:} ls:& fo:| rl:( n4:( ss:| de:] js:| ch:? sh:( mo:| zu:)
  1. Lieber Robert,

    "funktioniert nicht" ist keine Problembeschreibung. Ich kann aus Deinem Code so auf anhieb nicht erkennen, was bei Dir was wie macht, bzw eben nicht macht. Du solltest unbedingt in einem solchen Falle genau schildern, was Du bezweckt hast, und was bisher geschieht (sehr hilfreich: Fehlermeldungen)!

    function start()

    {
                for (var i = 0; i < 3; i++)
                {
                   var box = document.getElementById("box");
                   var a = document.createElement("a");
                   a.href = "#box_" + i;
                   a.onclick = function () { showbox(i); };
                   a.appendChild(document.createTextNode("showbox(" + i + ")"));

    box.appendChild(a);
                }
             }

      
    Du könntest den Parameter für showbox() aus dem href-Attribut des angeklickten Links herausfiltern.  
      
    ~~~javascript
    a.href = "#box_" + i;  
    a.onclick = function () {  
        var i = this.href.replace(/.*(\d+)$/, "$");  
        return showbox(i);  
    };
    

    Warum die Referenz der Variablen "i" in Deinem Code anscheinend nicht an die Funktion im onclick-Eventhandler übergeben wird (hast Du das eigentlich überprüft? Hier greift Dein "funktioniert nicht!" besonders schlecht!) kann ich nicht sagen.

    Bitte debugge Deinen Code anständig und verrate mir, was aus dem i in Deinem Code bei dem Klick tatsächlich wurde. Mich würde das jetzt schon interessieren, da ich hier was dazulernen kann!

    Liebe Grüße aus Ellwangen,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. "funktioniert nicht" ist keine Problembeschreibung. Ich kann aus Deinem Code so auf anhieb nicht erkennen, was bei Dir was wie macht, bzw eben nicht macht. Du solltest unbedingt in einem solchen Falle genau schildern, was Du bezweckt hast, und was bisher geschieht (sehr hilfreich: Fehlermeldungen)!

      Glaub mir, ich würde dir liebend gerne Fehlermeldungen geben... Wenn ich welche hätte

      Das ist die Ausgabe vom FireBug:
      http://img213.imageshack.us/img213/2738/fehlermeldungtk3.png
      Wieso ist da kein onclick-Attribut bei den Links?

      a.href = "#box_" + i;

      a.onclick = function () {
          var i = this.href.replace(/.*(\d+)$/, "$");
          return showbox(i);
      };

        
      Ich habe keine Ahnung was dein Code da macht, ich kenne mich mit Regexp nicht aus. Aber ich habe auch keine Ahnung WOZU du das machst. Bei onclick soll ja einfach nur die "showbox"-Funktion mit dem (numerischen) Parameter aufgerufen werden.  
        
      
      > Warum die Referenz der Variablen "i" in Deinem Code anscheinend nicht an die Funktion im onclick-Eventhandler übergeben wird (hast Du das eigentlich überprüft? Hier greift Dein "funktioniert nicht!" besonders schlecht!) kann ich nicht sagen.  
        
      Tja genau das ist es auch was ich mich frage, nur konnte ich es einfach nicht formulieren. Es wird scheinbar gar kein Eventhandler angelegt. Fehlermeldung wird aber auch keine ausgegeben...  
        
      
      -- 
      ie:% fl:| br:^ va:} ls:& fo:| rl:( n4:( ss:| de:] js:| ch:? sh:( mo:| zu:) 
      
      1. echo $begrüßung;

        Das ist die Ausgabe vom FireBug:
        http://img213.imageshack.us/img213/2738/fehlermeldungtk3.png
        Wieso ist da kein onclick-Attribut bei den Links?

        Es ist nicht im HTML-Code zu finden, weil es nicht dort hinzugefügt wurde sondern zum DOM-Element. Dort wirst du es finden.

        Fehlermeldung wird aber auch keine ausgegeben...

        Ich habe eine gesehen, als innerhalb von showbox() auf nicht vorhandene Eigenschaften des Objektes box zugegriffen werden sollte.

        echo "$verabschiedung $name";

        1. Es ist nicht im HTML-Code zu finden, weil es nicht dort hinzugefügt wurde sondern zum DOM-Element. Dort wirst du es finden.

          Ja ich verstehe jetzt wie du das meinst, es ist ja ein DOM-Eventhandler.
          Finden tu ich es im FireBug allerdings nicht.

          Fehlermeldung wird aber auch keine ausgegeben...

          Ich habe eine gesehen, als innerhalb von showbox() auf nicht vorhandene Eigenschaften des Objektes box zugegriffen werden sollte.

          Stimmt auch...

          --
          ie:% fl:| br:^ va:} ls:& fo:| rl:( n4:( ss:| de:] js:| ch:? sh:( mo:| zu:)
      2. Lieber Robert,

        a.href = "#box_" + i;

        a.onclick = function () {
            var i = this.href.replace(/.*(\d+)$/, "$");
            return showbox(i);
        };

        
        >   
        > Ich habe keine Ahnung was dein Code da macht, ich kenne mich mit Regexp nicht aus.  
          
        dieser Code resduziert den Inhalt des href-Attributes auf die Ziffer(n) am Ende, um so herauszufinden, welche Box wohl gemeint war. Wenn Du mit onclick oder anderen Eventhandlern eine Funktion ausführts, dann verweist "this" immer auf das angeklickte Element. Daher befindet sich in this.href das Verweisziel (z.B. "#box\_2"). Damit ist die Funktion in der Lage, die Ziffer im Moment des Klicks herauszufinden, um showbox() mit einer passenden Nummer aufzurufen.  
          
        War doch einfach, oder...?  
          
        Liebe Grüße aus [Ellwangen](http://www.ellwangen.de/),  
          
        Felix Riesterer.
        
        -- 
        ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
        
    2. echo $begrüßung;

      Warum die Referenz der Variablen "i" in Deinem Code anscheinend nicht an die Funktion im onclick-Eventhandler übergeben wird (hast Du das eigentlich überprüft? Hier greift Dein "funktioniert nicht!" besonders schlecht!) kann ich nicht sagen.

      Bitte debugge Deinen Code anständig und verrate mir, was aus dem i in Deinem Code bei dem Klick tatsächlich wurde. Mich würde das jetzt schon interessieren, da ich hier was dazulernen kann!

      Wenn du was dazulernen möchtest, kannst du molilys Artikel zur Organisation von JavaScripten lesen.

      for (var i = 0; i < 3; i++)
                     a.onclick = function () { showbox(i); };

      Das Problem ist, dass die Variable i und nicht deren aktueller Wert in den Eventhandler-Code eingebaut wird. Die Auswertung des Codes im Eventhandler findet erst beim Aufrufen statt. i ist somit immer 3, so wie es am Ende der for-Schleife hinterlassen wurde. Allerdings fällt mir leider kein eleganterer Weg außer eval() ein, um das Problem zu lösen.

      echo "$verabschiedung $name";

      1. Das Problem ist, dass die Variable i und nicht deren aktueller Wert in den Eventhandler-Code eingebaut wird. Die Auswertung des Codes im Eventhandler findet erst beim Aufrufen statt. i ist somit immer 3, so wie es am Ende der for-Schleife hinterlassen wurde. Allerdings fällt mir leider kein eleganterer Weg außer eval() ein, um das Problem zu lösen.

        Danke, das erklärt so einiges!

        Das:

          
        for (var i = 0; i < 3; i++)  
           a.onclick = function () { showbox(eval(i)); };  
        
        

        ändert leider trotzdem nichts am Gesamtergebnis. :(

        Oder wie gedenkst du eval() einzusetzen?

        --
        ie:% fl:| br:^ va:} ls:& fo:| rl:( n4:( ss:| de:] js:| ch:? sh:( mo:| zu:)
        1. echo $begrüßung;

          Das Problem ist, dass die Variable i und nicht deren aktueller Wert in den Eventhandler-Code eingebaut wird. Die Auswertung des Codes im Eventhandler findet erst beim Aufrufen statt. i ist somit immer 3, so wie es am Ende der for-Schleife hinterlassen wurde. Allerdings fällt mir leider kein eleganterer Weg außer eval() ein, um das Problem zu lösen.
          Danke, das erklärt so einiges!

          Das:

          for (var i = 0; i < 3; i++)

          a.onclick = function () { showbox(eval(i)); };

          
          > ändert leider trotzdem nichts am Gesamtergebnis. :(  
            
          Weil das immer noch das gleiche Prinzip ist. Der Code in der Eventhandler-Funktion wird \_nicht\_ während der Definition ausgewertet, egal, was du da hinzufügst.  
            
          
          > Oder wie gedenkst du eval() einzusetzen?  
            
          Ich dachte eher an sowas:  
            
            a.onclick = eval("function () { showbox(" + i + ") }")  
            
            
          P.S. Im OP sah ich dich HTML 1.1 verwenden. Suche bitte im Archiv, warum das keine gute Idee ist. Auch die XML-Deklaration ist nicht gerade förderlich, wenn man den IE6 berücksichtigen muss.  
            
            
          echo "$verabschiedung $name";
          
          1. Weil das immer noch das gleiche Prinzip ist. Der Code in der Eventhandler-Funktion wird _nicht_ während der Definition ausgewertet, egal, was du da hinzufügst.

            Stimmt natürlich...

            a.onclick = eval("function () { showbox(" + i + ") }")

            Das seltsame ist jetzt wieder, das egal was ich mit eval() dem Eventhandler zuweise immer einen Syntax Error ergibt...
            Ausserdem wäre das mit eval doch nicht hässlich, oder?

            P.S. Im OP sah ich dich HTML 1.1 verwenden. Suche bitte im Archiv, warum das keine gute Idee ist. Auch die XML-Deklaration ist nicht gerade förderlich, wenn man den IE6 berücksichtigen muss.

            Ja OK, danke für den Tipp, ich werde wohl einfach auf XHTML1.0-Strict umsteigen

            --
            ie:% fl:| br:^ va:} ls:& fo:| rl:( n4:( ss:| de:] js:| ch:? sh:( mo:| zu:)
            1. echo $begrüßung;

              a.onclick = eval("function () { showbox(" + i + ") }")
              Das seltsame ist jetzt wieder, das egal was ich mit eval() dem Eventhandler zuweise immer einen Syntax Error ergibt...

              Wie sehen deine Versuche aus? Ich hatte mit genau der Zeile im FF 2.0.0.16 das gewünschte Ergebnis.

              Ausserdem wäre das mit eval doch nicht hässlich, oder?

              Ja eben. Ich hoffe ja, dass noch jemand eine bessere Lösung weiß.

              echo "$verabschiedung $name";

              1. Wie sehen deine Versuche aus? Ich hatte mit genau der Zeile im FF 2.0.0.16 das gewünschte Ergebnis.

                IE 8/7:
                Meldung: Nicht implementiert
                Zeile: 27
                Zeichen: 6
                Code: 0

                Firebug (FF 3.0.1):
                syntax error @ Line 27/Zeichen 6
                function () { showbox(0) }

                Opera 9.5: Funktioniert

                Ausserdem wäre das mit eval doch nicht hässlich, oder?

                Ja eben. Ich hoffe ja, dass noch jemand eine bessere Lösung weiß.

                NICHT hässlich dachte ich
                Was ist daran hässlich?

                --
                ie:% fl:| br:^ va:} ls:& fo:| rl:( n4:( ss:| de:] js:| ch:? sh:( mo:| zu:)
                1. echo $begrüßung;

                  Wie sehen deine Versuche aus? Ich hatte mit genau der Zeile im FF 2.0.0.16 das gewünschte Ergebnis.

                  IE 8/7:
                  Meldung: Nicht implementiert
                  Zeile: 27
                  Zeichen: 6
                  Code: 0

                  Den seh ich im 6er IE auch, weiß aber nicht, was der da nicht will.

                  Firebug (FF 3.0.1):
                  syntax error @ Line 27/Zeichen 6
                  function () { showbox(0) }

                  Der 3er FF arbeitet nicht richtig mit W2K zusammen, konnte es deshalb nur im 2er problemlos testen.

                  Opera 9.5: Funktioniert

                  hab ich hier nicht

                  Ausserdem wäre das mit eval doch nicht hässlich, oder?

                  Ja eben. Ich hoffe ja, dass noch jemand eine bessere Lösung weiß.
                  NICHT hässlich dachte ich

                  Tschuldigung, das "nicht" hatte ich übersehen.

                  Was ist daran hässlich?

                  eval() ist eigentlich immer ein Zeichen dafür, dass der Programmierer keine Ahnung hatte, wie es ohne zu lösen geht. Wenn auch noch Benutzereingaben mit im Spiel sind, muss man besondere Vorsicht bei der Implementierung walten lassen, sonst bewahrheitet sich am Ende noch der Spruch "eval ist evil".

                  echo "$verabschiedung $name";

      2. for (var i = 0; i < 3; i++)
                       a.onclick = function () { showbox(i); };
        Das Problem ist, dass die Variable i und nicht deren aktueller Wert in den Eventhandler-Code eingebaut wird. Die Auswertung des Codes im Eventhandler findet erst beim Aufrufen statt. i ist somit immer 3, so wie es am Ende der for-Schleife hinterlassen wurde. Allerdings fällt mir leider kein eleganterer Weg außer eval() ein, um das Problem zu lösen.

        Als ich vor etwas Ähnlichem stand, habe ich das so ähnlich gelöst:

        for (var i=0; i<3; i++){  
          a.onclick=(function(x){return function(){showbox(x);};})(i);}
        

        Keine Verwendung von eval und die Closures, die einem hier den Streich spielen, werden sinnvoll eingesetzt. ;-)

        --
        Reden ist Silber, Schweigen ist Gold, meine Ausführungen sind Platin.
        Self-Code: sh:( ch:? rl:( br:> n4:( ie:{ mo:) va:) de:> zu:} fl:| ss:| ls:~ js:|
        1. Lieber Timo,

          for (var i=0; i<3; i++){

          a.onclick=(function(x){return function(){showbox(x);};})(i);}

            
          COOL!!! Das merke ich mir für später! Danke!  
            
          Liebe Grüße aus [Ellwangen](http://www.ellwangen.de/),  
            
          Felix Riesterer.
          
          -- 
          ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
          
        2. echo $begrüßung;

          for (var i = 0; i < 3; i++)
                         a.onclick = function () { showbox(i); };
          Das Problem ist, dass die Variable i und nicht deren aktueller Wert in den Eventhandler-Code eingebaut wird. Die Auswertung des Codes im Eventhandler findet erst beim Aufrufen statt. i ist somit immer 3, so wie es am Ende der for-Schleife hinterlassen wurde. Allerdings fällt mir leider kein eleganterer Weg außer eval() ein, um das Problem zu lösen.
          Als ich vor etwas Ähnlichem stand, habe ich das so ähnlich gelöst:

          for (var i=0; i<3; i++){

          a.onclick=(function(x){return function(){showbox(x);};})(i);}

            
          Aha, sieht verwendbar aus. [Augenblicke später] Funktioniert auch, zumindest im FF 2.0.0.15.  
            
          
          > Keine Verwendung von eval und die Closures, die einem hier den Streich spielen, werden sinnvoll eingesetzt. ;-)  
            
          Ich versuche mal die Arbeitsweise zu erklären. Ein ()-Klammernpaar und die Semikolons sind übrigens überflüssig.  
            
            a.onclick = function (x) { return function () { showbox(x) } } (i)  
            
          Deklariert wird eine anonyme Funktion, die einen Parameter entgegennimmt und in x zur Verfügung stellt. Das ist dieser Teil:  
            
            function (x) { ... }  
            
          Diese wird auch sofort mit i als Parameter aufgerufen:  
            
            function (x) { ... } (i)  
            
          Sie gibt per return eine weitere anonyme Funktion zurück, die den showbox-Aufruf enthält, der, wenn irgendwann später der Eventhandler zuschlägt, mit dem in x gemerkten Wert ausgeführt wird. Diese zweite anonyme Funktion wird dem Eventhandler zugewiesen.  
            
          Die äußere anonyme Funktion geht im Prinzip verloren, da keine Referenz mehr auf sie besteht. Sie bleibt aber irgendwo im Speicher erhalten, weil sie das x enthält, welches die innere Funktion bekommt.  
            
          Beim nächsten Schleifendurchlauf passiert das gleiche nochmal. Es wird eine neue äußere anonyme Funktion erstellt, die sofort mit dem nun um eins erhöhten Wert von i ausgeführt wird, usw. usf.  
            
            
          echo "$verabschiedung $name";
          
          1. Danke für die Erklärung und für die Hilfe im allgemeinen!
            Die Lösung ist perfekt.

            Funktioniert auch vollkommen Browser-unabhängig.
            Getestet auf Windows mit Opera 9.5, FF 3, IE8&7, Safari 3

            --
            ie:% fl:| br:^ va:} ls:& fo:| rl:( n4:( ss:| de:] js:| ch:? sh:( mo:| zu:)
        3. BESTEN DANK!
          Echt eine geniale Lösung, funktioniert wunderbar!
          Ich glaube ich wäre einfach NIE draufgekommen! :)

          --
          ie:% fl:| br:^ va:} ls:& fo:| rl:( n4:( ss:| de:] js:| ch:? sh:( mo:| zu:)