Oliver 123: anonyme Funktionen mit variablem Parameter im Schleifendurchlauf

Hallo zusammen,

Hintergrund/Aufgabenstellung:

Ich habe auf einer Webseite mehrere Informationsblöcke. Jeder Informationsblock umfasst 3 Absätze (p-tags). Der erste Absatz(mit der ID „pk(n)“)  enthält Kurz-Informationen, der zweite Absatz(mit der ID „pl(n)“) den gesamten Artikel und im dritten Absatz ist eine Download-Option des Artikels. Die Gesamtanzahl der Informationsblöcke ist nicht bekannt.

Im jeweils ersten Absatz ist ein Link (mit der ID „wl(n)“) eingebaut, worüber es möglich sein soll, den gesamten Artikel (Absatz 2) einzublenden und den kurzen Absatz (Absatz 1) auszublenden. Absatz 3 bleibt unberührt. Dieses Klick-Ereignis wird über einen Eventhandler überwacht.

Bei meinem Code möchte ich strikt nach dem MVC-Prinzip vorgehen, weswegen ich die Eventhandler nicht im HTML-Teil, sondern per Javascript, einfüge.

Der Javascript-Code:

window.onload = function ()  
{  
  init();  
}  
  
function init()  
{  
  var p_total = document.getElementsByTagName('p').length / 3;  
  for(var i = 1; i <= p_total; i++)  
  {  
    document  
      .getElementById('wl' + i)  
      .addEventListener('click', function() {an_aus(i);}, false);  
  }  
}  
	  
function an_aus(wert)  
{  
  document.getElementById('pk' + wert).style.display = "none";  
  document.getElementById('pl' + wert).style.display = "block";  
}

Problem:
Die Problemzeile in der Funktion init() liegt hier:

…  .addEventListener('click', function() {an_aus(i);}, false); …

Und zwar im Teil wo die Variable an die anonyme Funktion übergeben wird. Dieser Parameter hat immer den letzten Wert von der Schleifen-Variablen „i“ und führt beim Aufruf zu einem „undefined“ weil es den Absatz mit dieser ID ja nicht gibt. Übergebe ich jedoch keine Variable sondern eine „feste“ Zahl, wird der Code erwartungsgemäß ausgeführt.

Und an diesem Punkt bin ich grad mit meinem Latein am Ende. Wie erreiche ich, das bei dem Schleifendurchlauf zu dem Zeitpunkt der anonymen Funktion bei der Übergabe des Parameter „i“ auch jeweils der Laufzeitwert von „i“ übergeben und nicht der Endwert von „i“?

Abschließend noch zum Verständnis ein Auszug aus dem HTML-Teil:

<p class="presse_kurz" id="pk1">  
Lorem ipsum dolor sit amet, consetetur <a href="#" id="wl1">>> weiterlesen</a>.  
</p>  
  
<p class="presse_lang" id="pl1">  
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut  
labore et dolore magna aliquyam erat, sed diam voluptua.  
</p>  
  
<p class="pdf">  
<a href="#">Artikel downloaden</a>  
</p>  
  
...  
<script type="text/javascript" src="javascript_datei.js"></script>  
</body>  
</html>  

CSS – Klassen:

.presse_kurz  
{  
  display: block;  
}  
  
.presse_lang  
{  
  display: none;  
}

Viele Grüße
Oliver

  1. for(var i = 1; i <= p_total; i++)
      {
        document
          .getElementById('wl' + i)
          .addEventListener('click', function() {an_aus(i);}, false);
      }

    Und an diesem Punkt bin ich grad mit meinem Latein am Ende.

    So funktionieren Closures – sie konservieren das Variablen-Objekt der äußeren Funktion und erlauben somit den Zugriff auf diese Variablen über die Scope-Chain. Sie konservieren jedoch nicht auf den aktuellen Wert, den die Variablen zum Zeitpunkt der Erzeugung der Closure hatten.

    Wie erreiche ich, das bei dem Schleifendurchlauf zu dem Zeitpunkt der anonymen Funktion bei der Übergabe des Parameter „i“ auch jeweils der Laufzeitwert von „i“ übergeben und nicht der Endwert von „i“?

    Das könnte man mit einer weiteren Funktion lösen, bei sich der Wert von i nicht ändert:

    function registriereHandler (i) {  
      document  
        .getElementById('wl' + i)  
        .addEventListener('click', function() {  
          // Hier drin können wir sicher sein, dass i den korrekten, gleich bleibenden Wert hat  
          an_aus(i);  
        }, false);  
    }  
      
    for (var i = 1; i <= p_total; i++) {  
      registriereHandler(i);  
    }
    

    Das ist hinsichtlich Laufzeit-Performance und Speicherverwendung aber alles andere als optimal.

    Da du ohnehin schon die Zahl am Element speicherst, würde ich stattdessen die an_aus-Funktion umschreiben und die Zahl aus der ID extrahieren:

    .addEventListener('click', an_aus, false);

    und dann

    function an_aus () {  
      var nr = [link:http://molily.de/js/event-handling-objekt.html#currenttarget-target@title=this].id.match(/\d+$/)[0]; // aus "asdf123" wird "123"  
      if (!nr) return;  
      document.getElementById('pk' + nr).style.display = "none";  
      document.getElementById('pl' + nr).style.display = "block";  
    }
    

    Mathias

    1. Hallo Mathias,

      .addEventListener('click', an_aus, false);

      und dann

      function an_aus () {

      var nr = [link:http://molily.de/js/event-handling-objekt.html#currenttarget-target@title=this].id.match(/\d+$/)[0]; // aus "asdf123" wird "123"
        if (!nr) return;
        document.getElementById('pk' + nr).style.display = "none";
        document.getElementById('pl' + nr).style.display = "block";
      }

      
      >   
      > Mathias  
        
      vielen Dank, das bringt mich ein Riesenschritt vorwärts.  
        
      lg  
      Oliver