Alex: Variablenübergabe

Hallo,

ich möchte, dass in meinem javascript nach dem klicken auf ein bild eine funktion aufgerufen wird, außerdem soll dieser funktion eine variable mitgegeben werden. die bilder und die tabelle in der die bilder angezeigt werden, werden ebenfalls in javascript erzeugt. das problem ist das onclick es wird nur einmal ausgeführt, nämlich bei der erstellung der buttons. klickt man später auf die bilder passiert garnichts. ich hab oncklick bisher nur im html teil benutzt. was ist anders, wenn ich es in JS benutzen will?
hier mal der code:

  
function start() {  
    node = document.getElementById("table");  
    node.parentNode.insertBefore(createTable(11, 1, "table"), node);  
  
	function createTable(row, col, id) {  
	  
		var myTable     = document.getElementById("table");  
			var mytablebody = document.createElement("tbody");  
	  
			for(var j = 0; j < row; j++) {  
				mycurrent_row = document.createElement("tr");  
				for(var i = 0; i < col; i++) {  
						mycurrent_cell = document.createElement("td");  
						mycurrent_cell.setAttribute("ID", menu[j]);  
	  
								insertimg = document.createElement('img');  
								insertimg.setAttribute('src', "images/space.png");  
								insertimg.onclick=navi(j);/* um diesen befehl geht es. ist es besser onclick als setAttribute zu benutzen? is doch eigendlich unsinnig da es schließlich ein JS befehl ist, oder? */  
		  
  
						mycurrent_cell.appendChild(insertimg);  
						mycurrent_row.appendChild(mycurrent_cell);  
				}  
				mytablebody.appendChild(mycurrent_row);  
		}  
	  
		myTable.appendChild(mytablebody);  
		myTable.setAttribute("ID", id);  
		return myTable;  
	}  
  
}

vielen dank für eure Hilfe, hoffe ihr habt mein problem richtig verstanden ;-)
gruß alex

  1. Hi!

    ich möchte, dass in meinem javascript nach dem klicken auf ein bild eine funktion aufgerufen wird, außerdem soll dieser funktion eine variable mitgegeben werden.

    Eventhandler werden vom System aufgerufen und was dabei mitgegeben wird, ist festgelegt. Eigene Werte sind nicht dabei. Aber eine Referenz auf das auslösende Objekt. Dem kannst du ein Attribut geben, auf welches du über die übergebenen Referenz zugreifen kannst.

      						insertimg.onclick=navi(j);/\* um diesen befehl geht es. ist es besser onclick als setAttribute zu benutzen? is doch eigendlich unsinnig da es schließlich ein JS befehl ist, oder? \*/  
    

    Mach dir den Unterschied zwischen einer Funktionsreferenz und einem Funktionsaufruf klar. Eine Funktion wird aufgerufen, wenn hinter ihrem Namen Klammern notiert sind. Somit hast du einen Funktionsaufruf notiert, dessen _Ergebnis_ du dem onclick-Handler zuweist.

    Lo!

    1. heißt das: ich brauche eine variable in der das ergebnis des eventhandlers gespeichert wird? ändert sich dieses wird eine funktion aufgerufen:

      var klick = false;  
        
      klick=insertimg.onClick;  
      								if (klick == true){  
      									navi(j);
      
      							}
      
      1. Hi!

        heißt das: ich brauche eine variable in der das ergebnis des eventhandlers gespeichert wird?

        Nein. Der Eventhandler hängt doch an einem Element, das in deinem Fall innerhalb der Schleife von insertimg repräsentiert wird. Diesem erzeugst du eine neue Eigenschaft, der du den Wert in j zuweist. onclick bekommt nur navi zugewiesen, also eine Referenz (und keinen Aufruf) auf die Funktion. Innerhalb von navi kannst du mit this.deine_eigenschaft auf den Wert von ehemals j zugreifen.

        Lo!

        1. hab's immer noch nicht ganz verstanden:

          »»...Diesem erzeugst du eine neue Eigenschaft, der du den Wert in j zuweist.

          ich weise insertimg eine egenschaft zu, z.B. eine ID und gebe der den wert j. also:

          insertimg.setAttribute('ID', j);

          »»onclick bekommt nur navi zugewiesen, also eine Referenz (und keinen Aufruf) auf die Funktion.

          insertimg.onClick=navi;

          »»Innerhalb von navi kannst du mit this.deine_eigenschaft auf den Wert von ehemals j zugreifen.

          function navi(){  
          	alert(this.ID);  
          	}
          
          1. Hi!

            ...Diesem erzeugst du eine neue Eigenschaft, der du den Wert in j zuweist.
            ich weise insertimg eine egenschaft zu, z.B. eine ID und gebe der den wert j. also:
            insertimg.setAttribute('ID', j);

            ID könntest du nehmen, das unterschiedet sich von id und wäre eine neue Eigenschaft. Aber die kannst du auch einfach zuweisen: insertimg.ID = j;

            onclick bekommt nur navi zugewiesen, also eine Referenz (und keinen Aufruf) auf die Funktion.
            insertimg.onClick=navi;

            onclick, nicht onClick.

            Innerhalb von navi kannst du mit this.deine_eigenschaft auf den Wert von ehemals j zugreifen.

            function navi(){

            alert(this.ID);
            }

              
            Passt.  
              
            Aber siehe [molily](https://forum.selfhtml.org/?t=206777&m=1404432), der hat noch viel mehr und bessere Ideen.  
              
              
            Lo!
            
          2. Hallo,

            hab's immer noch nicht ganz verstanden:

            scheint so ...

            ...Diesem erzeugst du eine neue Eigenschaft, der du den Wert in j zuweist.
            ich weise insertimg eine egenschaft zu, z.B. eine ID und gebe der den wert j. also:
            insertimg.setAttribute('ID', j);

            Nein. so weist du dem HTML-Elementobjekt ein Attribut zu. Warum? Setze doch direkt die Javascript-Objekteigenschaft:

            insertimg.ident=j;

            Ich habe hier bewusst nicht 'ID' oder 'id' gewählt, damit man es nicht mit dem HTML-Attribut (und der gleichnamigen Objekteigenschaft) verwechselt.

            onclick bekommt nur navi zugewiesen, also eine Referenz (und keinen Aufruf) auf die Funktion.
            insertimg.onClick=navi;

            Nein. Der Eventhandler heißt onclick, nicht onClick. Deine oben zitierte Anweisung ist syntaktisch korrekt und wird keinen Fehler auslösen. Aber sie bleibt wirkungslos, weil du nur eine neue Eigenschaft hinzufügst, die von niemandem beachtet wird.

            Innerhalb von navi kannst du mit this.deine_eigenschaft auf den Wert von ehemals j zugreifen.

            function navi(){

            alert(this.ID);
            }

              
            Genau. Oder this.ident, wenn du meinen alternativen Namensvorschlag aufgreifen möchtest.  
              
            Ciao,  
             Martin  
            
            -- 
            Der Professor sitzt beim Essen in der Mensa. Ein Student setzt sich ihm unaufgefordert gegenüber.  
            Professor: Seit wann essen denn Schwein und Adler an demselben Tisch?  
            Student:   Na gut, dann flieg' ich eben zum nächsten Tisch.  
            Selfcode: fo:) ch:{ rl:| br:< n4:( ie:| mo:| va:) de:] zu:) fl:{ ss:) ls:µ js:(
            
            1. insertimg.setAttribute('ID', j);

              Nein. so weist du dem HTML-Elementobjekt ein Attribut zu. Warum? Setze doch direkt die Javascript-Objekteigenschaft:

              In dem konkreten Fall ist es verschmerzbar, allgemein gibt es verschiedene Gründe, warum das nicht so klug ist, darunter:
              What's wrong with extending the DOM

              Beispielsweise HTML5-Data-Attribute und dataset zu nutzen ist schon eine besser Variante. jQuerys data-Methode arbeitet etwa mit einem zentralen Store und speichert nur einen zufälligen String-Key am Element, um Memory-Leaks zu vermeiden.

              Mathias

  2. Mahlzeit Alex,

    insertimg.onclick=navi(j);/* um diesen befehl geht es. ist es besser onclick als setAttribute zu benutzen? is doch eigendlich unsinnig da es schließlich ein JS befehl ist, oder? */

    Wie dedlfix bereits schrieb, weist Du an dieser Stelle der Eigenschaft "onclick" des Objekts "insertimg" den http://de.selfhtml.org/javascript/sprache/funktionen.htm#rueckgabewert@title=Rückgabewert des Funktionsaufrufs "navi(j)" zu.

    Was Du willst, ist eher folgendes: wenn der Event-Handler des entsprechenden Objekts ausgelöst wird, soll der Funktionsaufruf "navi(j)" erfolgen. Dazu könntest Du diesen z.B. in eine anonyme Funktion kapseln:

    insertimg.onclick = function() {  
      navi(j);  
    };
    

    Beim Klick auf das Objekt "insertimg" wird somit diese namenlose Funktion aufgerufen, innerhalb derer wiederum der von Dir gewünschte Funktionsaufruf erfolgt.

    MfG,
    EKKi

    --
    sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
    1. Hi EKKi,
      der von dir gepostete Code würde wahrscheinlich nicht das gewünschte Ergebnis erzielen.

      insertimg.onclick = function() {

      navi(j);
      };

        
      Da die Variable "j" immer den letzten Schleifenwert besitzen würde.  
        
      Eine Variante die klappen sollte, schaut so aus:  
      ~~~javascript
        
      insertimg.onclick = (function(j){  
      return function(){navi(j);}  
      })(j)  
      
      

      Gruß Metalgurke

      1. Hatte das Semikolon hinter "...})(j)" vergessen.

        insertimg.onclick = (function(j){
        return function(){navi(j);}
        })(j);

      2. Mahlzeit Metalgurke,

        Eine Variante die klappen sollte, schaut so aus:

        insertimg.onclick = (function(j){
        return function(){navi(j);}
        })(j)

          
        Ihr habt natürlich [beide](https://forum.selfhtml.org/?t=206777&m=1404419) Recht ...  
          
          
        MfG,  
        EKKi  
        
        -- 
        sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
        
      3. Hallo,

        Eine Variante die klappen sollte, schaut so aus:

        insertimg.onclick = (function(j){
        return function(){navi(j);}
        })(j)

          
        Wenn man eine schnelle Lösung sucht, ist das in Ordnung, in gutem Code sollte man dieses Muster möglichst vermeiden (siehe [Performance von JavaScript-Closures](http://molily.de/weblog/closures-performance)). Es gibt fast immer besser skalierende Lösungen, als n Funktionsobjekte in Schleifen anzulegen.  
          
        Obigen Code sollte man zumindest so optimieren, dass nicht in jedem Schleifendurchlauf zwei neue Funktionen erzeugt wird, wovon die erste sofort wieder weggeworfen wird (gut, das optimieren manche Engines wahrscheinlich weg):  
          
        ~~~javascript
        function getHandler (j) {  
          return function () {  
            navi(j);  
          };  
        }  
        insertimg.onclick = getHandler(j);
        

        Besser sind natürlich dedizierte, optimierte Funktionen für Binding und Currying (wie Function.prototype.bind), siehe dazu auch obigen Artikel.
        Auf Closures zu verzichten, etwa mit Event-Delegation, ist meistens die vorteilhafteste Lösung.

        Mathias

    2. Hi!

      Was Du willst, ist eher folgendes: wenn der Event-Handler des entsprechenden Objekts ausgelöst wird, soll der Funktionsaufruf "navi(j)" erfolgen. Dazu könntest Du diesen z.B. in eine anonyme Funktion kapseln:

      insertimg.onclick = function() {

      navi(j);
      };

        
      Das wird so nichts, denn beim vom Event ausgelösten Aufruf wird nicht der "damals" bei der Erstellung der Funktion aktuelle Wert von j übergeben sondern der derzeit aktuelle. Also jeder Eventhandler der Bilder bekommt immer die selbe Zahl, den Endwert von j nach Abarbeiten der Schleife.  
        
        
      Lo!
      
  3. Hallo,

    ich hab oncklick bisher nur im html teil benutzt. was ist anders, wenn ich es in JS benutzen will?

    Sehr viel. Siehe JavaScript: Grundlagen zur Ereignisverarbeitung und die Folgeseiten zum Event-Handling.

    function start() {
        node = document.getElementById("table");

    Wenn keine globalen Variablen nötig sind, sollte man lokale Funktionsvariablen verwenden – hier fehlt dafür das »var«. Dasselbe bei mycurrent_row und mycurrent_cell.

    mycurrent_cell.setAttribute("ID", menu[j]);
    insertimg = document.createElement('img');
    insertimg.setAttribute('src', "images/space.png");

    setAttribute brauchst du eigentlich nie. Du kannst in der Regel einfach
    insertimg.src = "images/space.png";
    schreiben. Das geht auch für viele andere Attribute wie etwa id.

    insertimg.onclick=navi(j);/* um diesen befehl geht es. ist es besser onclick als setAttribute zu benutzen? is doch eigendlich unsinnig da es schließlich ein JS befehl ist, oder? */

    Es wäre möglich, folgendes zu notieren:

    insertimg.setAttribute('onclick', 'navi(' + j + ')');

    Das ist aber nicht so kompatibel wie die klassische Variante, bei der man der onclick-Eigenschaft ein Funktionsobjekt zuweist.

    Andere Möglichkeiten wären:

    • Mit jedem Schleifendurchlauf eine Closure erzeugen. (Siehe die bisherigen Antworten.)

    • Informationen am Element speichern, welches den Event-Handler trägt, und in der Handlerfunktion diese auslesen (siehe Event-Objekt, verarbeitendes Element). Du speicherst ja schon die ID beim td-Element, damit könntest du bereits arbeiten.

    insertimg.setAttribute('data-row', j);  
    insertimg.onclick = navi;  
      
    function navi (e) {  
      var row = this.getAttribute('data-row');  
      alert(row);  
    }
    
    • Per Event-Delegation nur einen Event-Handler pro Zeile registrieren, denn alle Bilder einer Zeile scheinen denselben Event-Handler zu haben. Darin die nötigen Informationen beschaffen, wenn nötig über das Zielelement.
    mycurrent_row.setAttribute('data-row', j);  
    mycurrent_row.onclick = navi;
    

    navi wie oben

    Du hast anscheinend ohnehin schon eine separate Datenstruktur »menu«, welche du verwenden könntest. Wahrscheinlich musst du gar keine Zusatzinformationen im DOM speichern.

    Mathias

    1. hi,

      vielen dank für die ausführliche antwort. auch für den hinweis zu den globalen variablen. bin immer dankbar wenn man mir sagt wie man "effektiver" programmieren kann :-)

      von Closure hab ich noch nie was gehört deshalb konnte ich nicht viel damit anfangen. werd mir aber mal den artikel in den grundlagen durchlesen, wenn ihr meint es sei die eleganteste variante.

      so lange funktioniert es mit dieser methode:

      function start() {  
          var node = document.getElementById("table");  
          node.parentNode.insertBefore(createTable(11, 1, "table"), node);  
        
      	function createTable(row, col, id) {  
      	  
      		var myTable     = document.getElementById("table");  
      			var mytablebody = document.createElement("tbody");  
      	  
      			for(var j = 0; j < row; j++) {  
      				var mycurrent_row = document.createElement("tr");  
      				for(var i = 0; i < col; i++) {  
      						var mycurrent_cell = document.createElement("td");  
      						mycurrent_cell.setAttribute("ID", menu[j]);  
      	  
      								insertimg = document.createElement('img');  
      								insertimg.src = "images/space.png";  
      								  
      						mycurrent_cell.onclick = navi;  
      						mycurrent_cell.appendChild(insertimg);  
      						mycurrent_row.appendChild(mycurrent_cell);  
      				}  
      				mytablebody.appendChild(mycurrent_row);  
      		}  
      	  
      		myTable.appendChild(mytablebody);  
      		myTable.setAttribute("ID", id);  
      		return myTable;  
      	}  
        
      }
      

      und als berwei das es funzt:

      function navi (e) {  
        var row = this.getAttribute('ID');  
        alert(row);  
      }
      

      vielen dank nochmal
      gruß alex

    2. @@molily:

      nuqneH

      setAttribute brauchst du eigentlich nie.

      Sag niemals nie.

      Qapla'

      --
      Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
      (Mark Twain)
      1. Hi,

        setAttribute brauchst du eigentlich nie.

        Sag niemals nie.

        Da dürfte dann aber doch auch var ultimateAnswerData = ultimateAnswerElement['data-ultimate-answer']; browserübergreifend gehen oder?

        ~dave

        1. @@dave:

          nuqneH

          Sag niemals nie.

          Da dürfte dann aber doch auch var ultimateAnswerData = ultimateAnswerElement['data-ultimate-answer']; browserübergreifend gehen oder?

          Nein.

          Es wäre auch nicht verständlich, warum das gehen sollte, wenn
          var ultimateAnswerData = ultimateAnswerElement.dataUltimateAnswer;
          nicht geht.

          Qapla'

          --
          Gut sein ist edel. Andere lehren, gut zu sein, ist noch edler. Und einfacher.
          (Mark Twain)