Adi K.: Arrays: Knotenreferenzen als Indizes

Hallo!

Ich möchte gerne in einem Array speichern welche Dokumentknoten zusammengehören. Also zum Beispiel getElementsById('foo') gehört zu getElementsById('bar'). Diese Knoten sollen nicht über ein Universalattribut, welches eindeutig ist (wie z.B. "id"), gekennzeichnet sein müssen (also beliebige Knoten) und sind immer desselben Typs (HTMLInputElement).

Ich habe es also so versucht:
A = new Array();
e = getElementsById('foo');
A[e] = getElementsById('bar');

Das funktioniert nur bedingt: Als Index wird nur der Typ, aber nicht der Knoten (also Referenz auf den Knoten) gespeichert...

Wie könnte ich das realisieren??

Gruss,
Adi K.

PS: Folgendes kommt beim Experiment heraus:

  
A = new Array();  
a = getElementsById('foo'); // (Typ: HTMLInputElement)  
b = getElementsById('bar'); // (Typ: HTMLInputElement)  
c = getElementsById('xxx'); // (Typ: HTMLTextAreaElement)  
A[a] = 'Das ist foo';  
A[b] = 'Das ist bar';  
A[c] = 'Das ist xxx';  
alert(A[a]); // (Ausgabe: Das ist bar !!!)  
alert(A[b]); // (Ausgabe: Das ist bar)  
alert(A[c]); // (Ausgabe: Das ist xxx)  

  1. Sup!

    Was soll das genau bringen, zu wissen, ob foo zu bar gehört? Besonders unter dem Aspekt, dass Du so nicht unbedingt herausbekommen kannst, das auch bar zu foo gehört?

    Gruesse,

    Bio

    --
    Never give up, never surrender!!!
    1. Was soll das genau bringen, zu wissen, ob foo zu bar gehört?

      Für bessere Checkboxen: Wenn man auf ein grosses <td> klickt, soll es die Checkbox ankreuzen.

      so nicht unbedingt herausbekommen kannst, das auch bar zu foo gehört?

      Das ist auch nicht nötig...

      1. Sup!

        Für bessere Checkboxen: Wenn man auf ein grosses <td> klickt, soll es die Checkbox ankreuzen.

        Aber wenn Du eh vorher so ein Array aufbauen müsstest, könntest Du doch genau so gut gleich ins td 'foo' ein onClick="document.getElementById('bar').checked = true" schreiben?

        Gruesse,

        Bio

        --
        Never give up, never surrender!!!
        1. Hallo,

          Für bessere Checkboxen: Wenn man auf ein grosses <td> klickt, soll es die Checkbox ankreuzen.

          Aber wenn Du eh vorher so ein Array aufbauen müsstest, könntest Du doch genau so gut gleich ins td 'foo' ein onClick="document.getElementById('bar').checked = true" schreiben?

          oder im <td> nach der Checkbox suchen ganz ohne lästige Id-Vergabe

            
          <td onclick="ankreuzen(this)">;  
          
          
            
          function ankreuzen(elem) {  
           var ips=elem.getElementsByTagName("input");  
           if (ips.length > 0 ) {  
            var cb=ips[0].type=="checkbox" ? ips[0] : null ;  
            if (cb) cb.checked = ! cb.checked;  
            }  
           }  
          
          

          Gruß plan_B

          --
               *®*´¯`·.¸¸.·
  2. Danke für die Inputs!

    Ich werde morgen mal mein Code posten, damit ihr seht, was ich meine... Jetzt hab ich noch viel zu tun... :(

    Gute Nacht!
    Adi

  3. Hi

    PS: Folgendes kommt beim Experiment heraus:

    A = new Array();
    a = getElementsById('foo'); // (Typ: HTMLInputElement)
    b = getElementsById('bar'); // (Typ: HTMLInputElement)
    c = getElementsById('xxx'); // (Typ: HTMLTextAreaElement)
    A[a] = 'Das ist foo';
    A[b] = 'Das ist bar';
    A[c] = 'Das ist xxx';
    alert(A[a]); // (Ausgabe: Das ist bar !!!)
    alert(A[b]); // (Ausgabe: Das ist bar)
    alert(A[c]); // (Ausgabe: Das ist xxx)

      
    Ich schlag es jetzt nicht nach, aber meine Vermutung:  
      
    wenn von getElement-s-ById gesprochen wird (PLURAL), handelt es sich um ein Array im Return.  
      
    Du weist es aber einem "Skalar" ... ähm ... Einzelelement zu also wird das Objekt stringified, was bei denen die Rückgabe eines Typ-Strings bedeutet.  
      
    Wenn du sicher bist dass es nur ein foo oder bar gibt dann solltest du Arrayelement [0] abrufen.  
      
    Alles klar?  
     Kurt  
      
    
    
    1. außerdem ...

      ich hab so meine Zweifel ob du mit einem Array hinkommst, die Objektreferenzen werden ziemlich groß!
      Wenn dann sollte es schon ein Hash sein.

      Und überhaupt wenn du zu Node-Objekten Informationen ablegen möchtest, warum legst du sie nicht im Node selbst ab?

      getElementsById("foo")[0].zusatzInfo='mach misch nachisch';

      Alles Klar?
       Kurt

  4. e = getElementsById('foo');

    ächZ noch einer der Fantasie-Code postet...

    getElementById() (HTML-Elementzugriff über id-Attribut)
    getElementsByName() (HTML-Elementzugriff über name-Attribut)
    getElementsByTagName() (HTML-Elementzugriff über Elementliste)

    http://de.selfhtml.org/javascript/objekte/document.htm

    WARUM ????... nur für den Kick und und den Augenblick?

    seufZ

  5. Weiter unten steht der Source-Code, wo ich den Array gebraucht hätte. Ich habe es nun mit Hilfe des Tipps von KurtZ (Danke!) realisiert, finde aber die Methode nicht besonders elegant. Meine Frage ist deshalb immernoch aktuell:
    Kann man Knotenobjekte irgendwie als Index eines Arrays brauchen?

    Gruss,
    Adi

    PS: Ich meinte natürlich getElementById('x')

    ----

      
    /*  
     * Cell Clicker v1.0  
     * (C) Adrian Kousz 2007  
     * Released under the terms of the LGPL 3  
     * http://www.gnu.org/licenses/lgpl.html  
     *  
     * Embedding:  
     * In header: <script type="text/javascript" src="CellClicker2.js"></script>  
     * At the end of body: <script>makeClickable()</script>  
     */  
      
    var clickClass = 'ic'; // the class name of the clickable element  
    var hoverColor = 'black';  
      
    var correl = new Array();  
    function makeClickable() {  
        var inputs = new Array();  
        var curr;  
        var button;  
        inputs = document.getElementsByTagName('input');  
        for (var i=0;i<inputs.length;i++) {  
            curr = inputs[i];  
            if (curr.type == 'radio' || curr.type == 'checkbox') {  
                if (button = findClickable(curr)) {  
                    button.correl = (Math.random()*1000000).toFixed(0);  
                    correl[button.correl] = curr;                // <- Die temporäre Lösung  
                    button.onmouseover = function() {normalColor = this.style.backgroundColor; this.style.backgroundColor = hoverColor}  
                    button.onmouseout = function() {this.style.backgroundColor = normalColor}  
                    button.onclick = function() {correl[this.correl].checked = !correl[this.correl].checked}  
                    curr.onclick = function() {this.checked = !this.checked}  
                }  
            }  
        }  
    }  
      
    function findClickable(e) {  
        var n = e;  
        while (n.className != clickClass && n.nodeType != 9) {n = n.parentNode}  
        if (n.nodeType == 9) {return undefined}  
        else {return n}  
    }  
    
    
    1. Moin!

      Weiter unten steht der Source-Code, wo ich den Array gebraucht hätte. Ich habe es nun mit Hilfe des Tipps von KurtZ (Danke!) realisiert, finde aber die Methode nicht besonders elegant. Meine Frage ist deshalb immernoch aktuell:
      Kann man Knotenobjekte irgendwie als Index eines Arrays brauchen?

      Ich bezweifle, dass du sowas benötigst. Konzentriere dich auf die wirkliche Aufgabe: Du willst ein ganzes TD anklicken können, und dadurch die darin befindliche Checkbox "treffen", also deren Zustand wechseln.

      Du mußt also jedem TD ein onclick-Event zuweisen, welches sich dann von "this" (dem TD) ausgehend im DOM-Baum abwärts arbeitet zum Input-Element des Typs Checkbox.

      Mit jQuery wäre das kein Problem. Ohne dass ich da jetzt großartig was getestet habe, würde ich es so anfangen:

        
      $(document).ready(function(){  
        $('td').click(function(){$('input:checkbox',this).click()});  
      });  
      
      

      Aber selbst ohne unterstützende Bibliotheken ist diese Aufgabe IMHO nicht allzu komplex. onclick this.getElementsByTagName('input') aufrufen, jedes gefundene Element auf korrekten Typ (Checkbox) prüfen und dann den checked-Zustand umkehren.

      - Sven Rautenberg

      --
      "Love your nation - respect the others."
    2. Hallo,

      Mach es, wie Sven sagt. Ich werde trotzdem mal beispielhaft erklären, wie du solche Probleme ohnehin vermeiden kannst.

      Zuerst einmal brauchst du keinen globalen Array zum Speichern, sondern kannst die Referenzen in dem Kontext speichern, wo sie gebraucht werden. Du kannst Referenzen einfach an anderen Elementobjekten speichern. Du willst ein Element (in deinem Code: button) mit einem Input-Feld (in deinem Code: curr) verknüpfen. Also verknüpfst du sie, indem du eine Referenz des einen als Eigenschaft beim anderen speicherst:

      button.zugehörigesEingabefeld = curr;

      In button.onclick hast du nun mit this Zugriff auf das »Button«-Element. Also kommst du - logischerweise - über this.zugehörigesEingabefeld an das zugehörige Eingabefeld. So einfach ist das. Ein globaler Array, der die Zuordnungen speichert, wird nicht benötigt.

      Man kann auch noch hochgestochener JavaScript schreiben, dann braucht man diese Referenz nicht unbedingt, weil man durch verschachtelte Funktionen dafür sorgen kann, dass in der click-Handlerfunktion einfach die curr-Variabgle verfügbar ist. Das ist in deinem Code auch schon der Fall, aber die curr-Variable wechselt in der Funktion makeClickable den Wert, sodass eine eindeutige Zuordnung nicht möglich wäre. Mit einer Helferfunktion ginge es aber:

      function setHandler (button, input) {
         button.onclick = function (e) {
            alert(input); // ist hier direkt verfügbar
         };
      }

      In der Schleife:

      setHandler(button, curr);

      Man notiert eine Funktion, die zwei Parameter erwartet und führt sie in der Schleife aus mit den beiden Elementobjekten als Parameter. Diese Funktion fügt den Handler hinzu. Durch die Verschachtelung ist in der onclick-Funktion die lokale Variable input aus dem Scope der setHandler-Funktion verfügbar. Diesen Effekt nennt man Closure.

      Mathias

      1. Hallo Molily

        Diesen Effekt nennt man Closure.

        Interessant das JS sowas kann... aber hast du Erfahrungswerte welche Browser Closures in JS korrekt verarbeiten?

        Je exotischer die Programmiertechnik umso weniger traue
        ich den Browsern...

        Grüße
         Kurt

        1. Interessant das JS sowas kann... aber hast du Erfahrungswerte welche Browser Closures in JS korrekt verarbeiten?

          Seit den 4'er Versionen (zumindest Netscape 3 kann es nicht)

          Je exotischer die Programmiertechnik umso weniger traue
          ich den Browsern...

          Wieso exotisch?

          Struppi.

          1. Hi

            Je exotischer die Programmiertechnik umso weniger traue
            ich den Browsern...

            Wieso exotisch?

            Wieviel Prozent der Programmierern traust du zu, zu wissen was ein Closure ist und wie man es einsetzt?

            Und ich erinnere mich das zumindest früher beim Opera alles was nicht Mainstream war zu eckliger Fehlersuche führte...

            Kurt

            1. Hallo,

              Wieviel Prozent der Programmierern traust du zu, zu wissen was ein Closure ist und wie man es einsetzt?

              Und für was soll das nun ein Argument sein? Keine Closures zu verwenden? Äh?? Dann wären extrem viele Kniffe gänzlich unmöglich. Lediglich der IE < 7 hatte ein Garbage-Collection-Problem, das im Zusammenhang mit Closures auftrat. Das ist aber recht leicht zu handeln und außerdem erzeugt mein Beispiel soweit ich weiß keine Memory-Leaks, weil nur zwei definierte Variablen im Scope der verschachtelten Funktion »vererbt« werden. (Was natürlich nicht zirkuläre Referenzen verhindert...)

              Mathias

            2. Wieviel Prozent der Programmierern traust du zu, zu wissen was ein Closure ist und wie man es einsetzt?

              Kommt darauf an was du unter Programmierer verstehst. Aber jemand der der sich mit Programmieren intensiv auseinandersetzt sollten closures bekannt sein, das ist kein Konzept was nur auf JS begrenzt ist.

              Und ich erinnere mich das zumindest früher beim Opera alles was nicht Mainstream war zu eckliger Fehlersuche führte...

              Du redest vermutlich vom DOM, da gab es tatsächlich eine Phase die etwas konfus war. Gerade die Zeit als IE4/NC4 (ich glaube Opera war damals bei 5 oder 6) auf dem Markt waren. Aber damals gab es auch keinen Mainstream. Das war dann irgendwann der IE 5 und da hatten dann alle Browser Schwierigkeiten.

              Struppi.

              1. Hi

                Kommt darauf an was du unter Programmierer verstehst. Aber jemand der der sich mit Programmieren intensiv auseinandersetzt sollten closures bekannt sein, das ist kein Konzept was nur auf JS begrenzt ist.

                tja vorrausschauend wollte ich auch erst "programmierendes Volk" sagen... sagen wir mal die die hier Fragen stellen und eigentlich dafür bezahlt werden es zu wissen.

                Du redest vermutlich vom DOM, da gab es tatsächlich eine Phase die etwas konfus war.

                DOM ist *mittlerweile* Mainstream. Es gab auch noch viel mehr konfuses ...

                Gerade die Zeit als IE4/NC4 (ich glaube Opera war damals bei 5 oder 6) auf dem Markt waren. Aber damals gab es auch keinen Mainstream. Das war dann irgendwann der IE 5 und da hatten dann alle Browser Schwierigkeiten.

                Auch die IE5 Zeit war furchtbar, ich habe immernoch Code im Umlauf, wo ich um die Bugs in Opera5 Workarounds programmiert habe.

                Damals war JS zumeist auf maximal 15 Zeiler für PopUps und Bildwechseln und Cookies usw. reduziert.

                Und das konnten auch alle Browser, weil Mainstream, mehr brauchten sie nicht.

                Ich glaube so richtig vollgenommen wird JS sowieso erst seit der "AJAX"/WEB2.0 Hype angefangen hat.

                Kurt

                PS: @Molily: Argument verstanden???

      2. Hallo molily

        Vielen Dank für deine Ausführliche Erklärung!
        Ich werde mir das Konzept morgen ansehen und meinen Code danach verbessern!

        @Sven: Nur weil ich ein kleines Funktiönchen von jQuery brauche, will ich dem Benutzer nicht zumuten, das herunterzuladen. Hierbei geht es weder um Optimierung der Ressourcen, noch um Schonung der Internetleitung, sondern um das Prinzip: Riesiege Librarys zu benützen, nur weil man eine Funktion daraus braucht und zu fault ist, sich selbst damit zu befassen, finde ich doof!
        (Aber lassen wir das. Das ist meine Meinung – und die Meinungen in diesem Thema gehen weit auseinander. Das wäre Off-Topic.)

        Vielen Dank nochmals an molily!
        Schönen Abend und bis morgen (ich werde die geschriebene Funktion wieder posten).
        Gruss
        Adi