s86s: onclick handler

grüße euch,

hoffe ihr könnt mir weiterhelfen, habe folgendes programmiert.

<script type="text/javascript">  
var track = true;  
  
function tracker (URL) {  
	var newURL = "http://cos-tools/IntranetTracking/Tracking/TrackPageRequest/?requestUrl="+ URL;  
	//location.href = newURL;  
	alert(newURL);  
}  
  
function prepareLinks() {  
	var a = document.getElementsByTagName('a');  
	alert (a.length);  
	for (i=0; i<a.length; i++) {  
		var uri = a[i].getAttribute('href');  
		a[i].setAttribute('href', '#');  
		//a[i].setAttribute('onclick', 'tracker(\''+uri+'\');');  
		a[i].onclick = function() {tracker(uri);};  
	}  
}  
  
var uri = document.URL;  
tracker(uri);  
  
if (track != false)  
{  
	prepareLinks();  
}  
  
</script>

es soll immer die URL ausgelesen werden und an die "tracker" function gehen.

wenn "track = true" sollen alle links gezählt werden und ein onclick an jedes href hinzugefügt werden, welches ebenfalls die "tracker" function anspricht.

egal wie ich die function verschiebe, entweder countet der mir "0" wie in diesem fall, oder wenn ich es verschiebe, countet er in meinem fall "2", jedoch geht immer die selbe url zum "tracker".

irgendwie stimmt mit der "prepareLinks" function etwas nicht.

danke.

  1. grüße euch,

    hoffe ihr könnt mir weiterhelfen, habe folgendes programmiert.

    <script type="text/javascript">

    var track = true;

    function tracker (URL) {
    var newURL = "http://bla.aspx?requestUrl="+ URL;
    //location.href = newURL;
    alert(newURL);
    }

    function prepareLinks() {
    var a = document.getElementsByTagName('a');
    alert (a.length);
    for (i=0; i<a.length; i++) {
    var uri = a[i].getAttribute('href');
    a[i].setAttribute('href', '#');
    //a[i].setAttribute('onclick', 'tracker(''+uri+'');');
    a[i].onclick = function() {tracker(uri);};
    }
    }

    var uri = document.URL;
    tracker(uri);

    if (track != false)
    {
    prepareLinks();
    }

    </script>

    
    >   
    > es soll immer die URL ausgelesen werden und an die "tracker" function gehen.  
    >   
    > wenn "track = true" sollen alle links gezählt werden und ein onclick an jedes href hinzugefügt werden, welches ebenfalls die "tracker" function anspricht.  
    >   
    > egal wie ich die function verschiebe, entweder countet der mir "0" wie in diesem fall, oder wenn ich es verschiebe, countet er in meinem fall "2", jedoch geht immer die selbe url zum "tracker".  
    >   
    > irgendwie stimmt mit der "prepareLinks" function etwas nicht.  
    >   
    > danke.
    
  2. Das Event bzw. der Handler heisst "click", nicht "onclick".

  3. @@s86s:

    nuqneH

    if (track != false)

    ?? Doppelte Verneinung?

    track ist ein boolescher Wert, also: if (track)

    Qapla'

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

    Du bist in eine Falle getappt, denn Du benutzt eine Variable, die in einer Closure steckt. Deshalb verhält sich Dein Code anders, als Du es erwarten würdest.

    function prepareLinks() {

    var a = document.getElementsByTagName('a');
    alert (a.length);
    for (i=0; i<a.length; i++) {
    var uri = a[i].getAttribute('href');
    a[i].setAttribute('href', '#');
    //a[i].setAttribute('onclick', 'tracker(''+uri+'');');
    a[i].onclick = function() {tracker(uri);};
    }
    }

      
    Zuerst fällt mir auf, dass Du eine Variableninstanziierung (oder wie auch immer man das nennt) mit dem Schlüsselwort "var" in einer Schleife mehrfach tust. Meines Wissens sollte das spätestens beim zweiten Schleifendurchlauf zu einer Fehlermeldung führen. Besser Du notierst ein "var uri;" nach oder vor Deinem "var a = ...;". Dann kannst Du in der Schleife "uri" ohne var davor benutzen.  
      
    Dann kommt der eigentliche Irrtum: Die Variable "uri" wird in der Schleife mit einem Wert befüllt. Dann wird in der Schleife ein Funktionsobjekt notiert, welches als Wert der onclick-Eigenschaft von a[i] zugewiesen wird. Es ist nun eine Eigenschaft von JavaScript, dass "uri" als Variablenobjekt innerhalb des Funktionsobjekts bekannt ist (daher kann der Wert aus "uri" verwendet werden), sodass auch Änderungen am Wert dieser Variable mit "erinnert" werden. Diesen Zusammenhang nennt man "Closure".  
      
    Wenn also i=0 ist, dann hat uri irgendeinen Wert. Der wird a[0] NICHT zugewiesen, sondern eine Referenz auf das Variablenobjekt "uri". Wenn später die Funktion in a[0].onclick aufgerufen wird, dann wird nachgeschaut, welchen Wert "uri" \_aktuell\_ hat und dieser dann benutzt. Du kannst Dir sicherlich denken, dass bei i=1 der Inhalt von "uri" mit einem neuen Wert befüllt wird, welcher dann sowohl in a[0].onclick als auch a[1].onclick Verwendung finden wird... um vom letzten Schleifendurchlauf dann zum letzten Mal ersetzt zu werden.  
      
    Alle Deine a-Elemente haben in ihrer onclick-Methode also einen identischen "uri"-Wert!  
      
    Dein Problem lässt sich einfacher lösen, als Du denkst. Wenn Du genau überlegst, dann wirst Du bestätigen können, dass "uri" lediglich das aktuelle Linkziel enthält. Stimmt's? Das bekommst Du auch anders, denn bei Aufruf von onclick ist innerhalb der Funktion das Schlüsselwort "this" eine Referenz auf das angeklickte a-Element selbst. Mittels "this.href" kannst Du nun also "uri" ersetzen und diese Variable restlos entsorgen:  
      
    ~~~javascript
    for (i=0; i<a.length; i++) {  
        a[i].onclick = function() {tracker(this.href);};  
    }
    

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. Zuerst fällt mir auf, dass Du eine Variableninstanziierung (oder wie auch immer man das nennt) mit dem Schlüsselwort "var" in einer Schleife mehrfach tust. Meines Wissens sollte das spätestens beim zweiten Schleifendurchlauf zu einer Fehlermeldung führen.

      Mehrfachdeklaration ist kein Problem. Variablendeklarationen werden durch »Hoisting« ohnehin nur einmal, nämlich beim Springen in den Funktionskontext vor Beginn der Ausführung des Funktionskörpers abgearbeitet.

      Wo man die Variable deklariert und wie häufig, ist insofern egal, manche raten dazu, sämtliche Variablen am Funktionsanfang zu deklarieren.

      Es ist nun eine Eigenschaft von JavaScript, dass "uri" als Variablenobjekt innerhalb des Funktionsobjekts bekannt ist (daher kann der Wert aus "uri" verwendet werden), sodass auch Änderungen am Wert dieser Variable mit "erinnert" werden. Diesen Zusammenhang nennt man "Closure".

      Ein Variablenobjekt ist etwas anderes als eine Variable. Der korrekte Begriff hier ist »Variable«. Siehe auch http://molily.de/javascript-core/

      Mathias

      1. Lieber molily,

        Mehrfachdeklaration ist kein Problem. Variablendeklarationen werden durch »Hoisting« ohnehin nur einmal, nämlich beim Springen in den Funktionskontext vor Beginn der Ausführung des Funktionskörpers abgearbeitet.

        das wusste ich so noch nicht. Mir war irgendwie in Erinnerung, dass folgendes zu einem Problem führt:

        function bar () {  
            var test = "test";  
            var a = 1;  
            var test = "Tester"; // Problem  
        }
        

        Ein Variablenobjekt ist etwas anderes als eine Variable. Der korrekte Begriff hier ist »Variable«. Siehe auch http://molily.de/javascript-core/

        Sachlich gesehen hast Du natürlich wieder mal Recht. Für jemanden, der das Prinzip mit den Closures noch nicht verstanden hat, ist es aber schneller nachvollziehbar, wenn man eben bei der Variable betont, dass nicht ihr Wert allein, sondern sie selbst "mit allem Drum und Dran" verarbeitet wird. Da ist die sachlich falsche Verwendung des Begriffs "Variablenobjekt" dem Verständnis einer Closure eher zuträglich, als die Verwendung des sachlich korrekten Begriffs.

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
        1. Mir war irgendwie in Erinnerung, dass folgendes zu einem Problem führt:

          function bar () {

          var test = "test";
              var a = 1;
              var test = "Tester"; // Problem
          }

            
          Zu welchem Problem soll das führen? Dieser Code ist identisch mit:  
            
          ~~~javascript
          var test, a;  
          test = "test";  
          a = 1;  
          test = "Tester";
          

          Die entsprechenden Verarbeitungsregeln der ECMAScript-Spezifikation habe ich in https://forum.selfhtml.org/?t=208504&m=1418668 zitiert.

          Für jemanden, der das Prinzip mit den Closures noch nicht verstanden hat, ist es aber schneller nachvollziehbar, wenn man eben bei der Variable betont, dass nicht ihr Wert allein, sondern sie selbst "mit allem Drum und Dran" verarbeitet wird. Da ist die sachlich falsche Verwendung des Begriffs "Variablenobjekt" dem Verständnis einer Closure eher zuträglich, als die Verwendung des sachlich korrekten Begriffs.

          Sorry, dass ich darauf herumreite ;), aber: In der Tat ist der Begriff Variablenobjekt in seiner *korrekten Verwendung* für das Verständnis von Closures sehr hilfreich und macht die Sache anschaulicher.

          Denn das Variablenobjekt mitsamt dessen Funktionsvariablen (Name-Wert-Paare) wird konserviert. Weil es taucht in der Scope-Chain der verschachtelten Funktion (der Closure) auftaucht. Ein Name (Identifier, Bezeichner) wird anhand der Scope-Chain aufgelöst, dabei werden mehrere Variablenobjekte durchlaufen und nach dem Namen durchsucht, um den zugehörigen Wert (bzw. eine Referenz) zu finden.

          Der springende Punkt ist, dass das Variablenobjekt immer dasselbe ist und bleibt und von allen angelegten Closures geteilt wird – daher hat das man das beschriebene Problem, wenn man Closures in Schleifen anlegt.

          Siehe:
          Das Variablenobjekt
          Die Scope-Chain (Kette von Gültigkeitsbereichen)

          Die Unterscheidung ist also durchaus hilfreich.

          Der korrekte Begriff für einen einzelnen Eintrag im Variablenobjekt (was du als »Variablenobjekt« bezeichnet hattest) nennt sich übrigens Binding, soweit ich weiß – das führt allerdings zu weit.

          Mathias

          1. Lieber molily,

            Sorry, dass ich darauf herumreite ;)

            aber nein, nicht entschuldigen! Dadurch, dass Du darauf herumreitest, lerne ich immer wieder etwas wertvolles dazu! Für mich ist das durchaus spannend, denn in aller Regel habe ich weder den Mut noch die Veranlassung, in den "Core" von JS gedanklich vorzustoßen.

            In der Tat ist der Begriff Variablenobjekt in seiner *korrekten Verwendung* für das Verständnis von Closures sehr hilfreich und macht die Sache anschaulicher.

            In diesem Fall hilft _mir_ die Unterscheidung zwischen "Variable" und "Variablenobjekt" tatsächlich weiter. Ob das aber für einen Laien auf einem früheren Lernstand ebenso hilfreicher ist, wage ich zu bezweifeln.

            Vielleicht können wir uns darauf einigen, dass für einen Laien das Verständnis von Closures im vorliegenden Beispielfall dadurch erleichtert wird, indem man ihn darauf hinweist, dass nicht der Wert alleine, sondern die ganze Variable in den jeweiligen Funktionsobjekten referenziert wird, sodass Änderungen an ihrem Wert von den in den Funktionsobjekten eingeschlossenen Referenzen "wahrgenommen" und "befolgt" werden.

            Sicherlich ist das Verständnis um die inneren Funktionsweisen einer JS-Engine hilfreich, um solche Zusammenhänge zu verstehen, es kann aber je nach eigenem Lernstand auch überfordern!

            Ein Name (Identifier, Bezeichner) wird anhand der Scope-Chain aufgelöst, dabei werden mehrere Variablenobjekte durchlaufen und nach dem Namen durchsucht, um den zugehörigen Wert (bzw. eine Referenz) zu finden.

            Ja, das ist des Browsers innere Programmierung. Aber ob diese spezielle Ausführung dem OP beim Verständnis von Closures wirklich weiterhilft, oder ob sie ihn im Moment eher verwirrt, kann wohl nur er beantworten. Ich tippe jedenfalls auf letzteres. ;-)

            Der korrekte Begriff für einen einzelnen Eintrag im Variablenobjekt (was du als »Variablenobjekt« bezeichnet hattest) nennt sich übrigens Binding, soweit ich weiß – das führt allerdings zu weit.

            Du sagst (bzw. schreibst) es. Ich danke Dir trotzdem für Deine Mühen!

            Liebe Grüße,

            Felix Riesterer.

            --
            ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)