Georg: Problem mit appendChild / removeChild /insertBefore

Hallo,

ich komme hier an einer Stelle einfach nicht mehr weiter und bräuchte Euren Rat.
Ich habe eine Tabelle in der Form hier

table
tbody
   tr
    td ... /td
   /tr
   tr
    td ... /td
   /tr
  ...
/tbody
/table

Was ich implementieren möchte ist eine funktion, um zwei Zeilen zu tauschen bzw, um eine Zeile nach unten|oben zu schieben.
Probleme dabei (Code unten): Bei der replaceChild-Methode wurde das Kind, mit welches das alte ersetzen sollte, gelöscht. Die insertBefore-Methode hat überhaupt nichs bewirkt.

Nun bin ich einen anderen Weg gegangen und habe versucht, die Zeilen zu löschen und später in veränderter Reihenfolge neu aufzubauen. Das klappt aber auch nicht, und jetzt seid ihr zunächst gefragt, zu ermitteln, warum das nicht ohne Weiteres so möglich.

Ich danke im Voraus ganz herzlich!

function move(parentName,elemName) {

parent = document.getElementById(parentName);
  nodes  = parent.childNodes;
  elem   = document.getElementById(elemName);

// neues Array zu Sichern der Kind-Knoten
  childArray = new Array();
  nrNodes = nodes.length;

// Bis hierher funktioniert alles ...
// nächste for-schleife: i=0 liefert ein text-Element
  var position;

// Array einlesen
  for (var i=1; i<nrNodes; i++) {
   childArray[i] = nodes[i];
  }

// Zeilen loeschen
  for (var i=1; i<nrNodes; i++) {
   parent.removeChild(nodes[i]);
  }

// ... und in neuer Reihenfolge einfuegen
  for (var i=1; i<nrNodes; i++) {
   parent.appendChild(childArray[i]);
  }
}

  1. Hallo Georg,

    // Zeilen loeschen
      for (var i=1; i<nrNodes; i++) {
       parent.removeChild(nodes[i]);
      }

    ich glaube, hier hakt es. Sobald du ein "Child" entfernst, rücken die anderen nach. Du löscht z.B. Nr. 0, dann wird die 1 zur 0, die 2 zur 1, etc.. Läsche immer die Nr. 0, also firstChild.

    Übrigens zählt Javascript, wie die meisten Programmiersprachen, Elemente von 0 ab.

    Gruß, Jürgen

    1. Hallo Jürgen,

      ok das ist schonmal ein guter Punkt; ich glaube aber es gibt noch mehr irrtümliche Annahmen...

      Ich gehe ja vom TBODY aus -- die Anzahl der Knoten stimmt auch jeweils mit der Anzahl meiner mittels TR gebildeten Zeilen überein, aber nun habe ich mir mittels alert(nodes[i]) Klarheit darüber verschafft, was für Objekte ich dort abfrage, und dort tauchen u.a. dann "undefined" und "text" auf. Ich weiß weder wo die herkommen noch welche Elemente das sein könnten.

      Vielleicht wäre das noch eine Stelle, wo ihr Ideen habt?
      der DOM-Inspektor von Mozilla zeigt diese Elemente auch an, aber gebildet habe ich sie eigentlich nie.

      Was ich in meinem Array mit den Nodes stehen haben möchte, sollten eigentlich nur die Kinder, d.h. die TRs meines TBODY sein.

      Hallo Georg,

      // Zeilen loeschen
        for (var i=1; i<nrNodes; i++) {
         parent.removeChild(nodes[i]);
        }

      ich glaube, hier hakt es. Sobald du ein "Child" entfernst, rücken die anderen nach. Du löscht z.B. Nr. 0, dann wird die 1 zur 0, die 2 zur 1, etc.. Läsche immer die Nr. 0, also firstChild.

      Übrigens zählt Javascript, wie die meisten Programmiersprachen, Elemente von 0 ab.

      Gruß, Jürgen

      1. Hallo Georg,

        je nach Browser sind Blanks und Zeilenumbrüche zwischen </td> und <td>, also zwischen den Tabellenknoten auch Knoten und damit Kinder des tbody. Wenn du dich nur für die TRs interessierst, versuch es mal mit document.getElementById("TabID").getElementsByTagName("tr").

        Gruß, Jürgen

  2. hi,

    Probleme dabei (Code unten): Bei der replaceChild-Methode wurde das Kind, mit welches das alte ersetzen sollte, gelöscht.

    // neues Array zu Sichern der Kind-Knoten
    childArray = new Array();
    // Array einlesen
    for (var i=1; i<nrNodes; i++) {
      childArray[i] = nodes[i];

    damit sicherst du dir m.E. nur die referenz auf ein element - wenn du dann aber dieses element selber entfernst, hast du allerhöchstens noch eine referenz, die ins nirwana zeigt ...

    kannst dir du das zu entfernende erste objekt nicht zunächst mittels clodeNode() in einem javascript-objekt als kopie sichern, dann entfernen, und woanders wieder einfügen?

    gruß,
    wahsaga

    --
    /voodoo.css:
    #GeorgeWBush { position:absolute; bottom:-6ft; }
  3. Hi,

    Nun bin ich einen anderen Weg gegangen und habe versucht, die Zeilen zu löschen und später in veränderter Reihenfolge neu aufzubauen. Das klappt aber auch nicht, und jetzt seid ihr zunächst gefragt, zu ermitteln, warum das nicht ohne Weiteres so möglich.

    Da es jedoch ohne Weiteres möglich ist hat sich dann Deine Frage erledigt? ;-)

    Aber Scherz beiseite.
    Wahsaga hat Dir schon einen guten Tip gegeben, aber falls er Dir zu sehr in's Detail geht hier nochmal in der Übersicht:

    Dein Problem hast Du ja schon sehr gut erkannt.

    Was ich implementieren möchte ist eine funktion, um zwei Zeilen zu tauschen

    Du benötigst also etwas, das man im Programmiererbereich mit Englisch als Lingua Franca für gewöhnlich "Swapping" nennt. Getauscht wird genauso gewöhnlich mittels eines temporären Speichers.

      
    function swap(one,two){  
      if(one && two){  
        var temp;  
        temp = one;  
        one  = two;  
        two  = temp;  
        return true;  
      }  
      return false;  
    }  
    
    

    Jetzt einfach einsetzen. "Einfach"? Ja, gut, aber _so_ schwer ist es auch nicht. Du mußt nur wissen, was genau Du austauschen möchtest. In Deinem Fall die Zeilen (Element "tr").
    Als Idee:

      
    function swapNodes(nodeOne, nodeTwo){  
      if(nodeOne && nodeTwo){  
        // Der Übersicht halber "Work on Copy".  
        // Aber wirklich _nur_ der Übersicht halber.  
        var copyOne  = document.getElementById(nodeOne);  
        var cloneOne = copyOne.cloneNode(true);  
      
        var copyTwo  = document.getElementById(nodeTwo);  
        var cloneTwo = copyTwo.cloneNode(true);  
      
        // Damit kann man jetzt oben beschriebenes Swapping  
        // ausführen.  
        copyOne.parentNode.replaceChild(cloneTwo, copyOne);  
        copyTwo.parentNode.replaceChild(cloneOne, copyTwo);  
      
        return true;  
      }  
      return false;  
    }  
    
    

    Auf die Gefahr hin mich zu wiederholen: obiger Code dient ausschließlich pädagogischen Zwecken und kann bei unsachgemäßer Anwendung zu bleibenden Schäden führen. Dito bei sachgemäßer Anwendung.

    Aber ich hoffe das Prinzip ist soweit klar.

    so short

    Christoph Zurnieden

    1. Hi,

      danke für die Antwort.
      Zunächst ein paar Korrekturen, um Klarheit zu schaffen.

      1. Mein im ersten Posting angegebener Code hat nicht funktioniert, weil beim Sichern der Nodes in myArray[] in myArray[0] ein text-Element gespeichert wurde, welches sich später als "undefined" herausstellte (Grund noch unklar...).
        Beim Einfügen der Elemente in der letzten Schleife hat dies dazu geführt, dass die Schleife einfach verlassen wurde, als das "undefined"-Element eingefügt werden sollte. Tja, ich mag Javascript schon aus diesem Grund einfach nicht, weil man es nicht zuverlässig debuggen kann.

      2. Zweites Posting von JürgenB.: Wenn man removeChild() anwendet, übergibt man keine Nummern sondern das Knoten-Objekt selbst an die Funktion. So funktioniert es auch, mit removeChild(Array[i]) in der Schleife zu arbeiten. Übrigens bleibt der Wert nodes.length innerhalb der Schleife konstant. (dekrementiert sich also nicht automatisch)

      3. Ich behaupte, dass _kein_ CallByReference, sondern CallByValue erfolgt. Wenn CallByReference (wie von meinem Vorschreiber gesagt) verwendet würde, müsste ich Zeiger in meinem "Sicherungs-Array" haben. Das ist aber nicht der Fall, JavaScript speichert Objekte, und daher funktioniert es auch, die Objekte wieder einzufügen, obwohl sie ja vorher gelöscht wurden.

      @Chritsoph:

      Auf die Gefahr hin mich zu wiederholen: obiger Code dient ausschließlich pädagogischen Zwecken und kann bei unsachgemäßer Anwendung zu bleibenden Schäden führen. Dito bei sachgemäßer Anwendung.

      Muss ich das verstehen? :-)

      Danke für alle Eure Antworten!

      Hi,

      Nun bin ich einen anderen Weg gegangen und habe versucht, die Zeilen zu löschen und später in veränderter Reihenfolge neu aufzubauen. Das klappt aber auch nicht, und jetzt seid ihr zunächst gefragt, zu ermitteln, warum das nicht ohne Weiteres so möglich.

      Da es jedoch ohne Weiteres möglich ist hat sich dann Deine Frage erledigt? ;-)

      Aber Scherz beiseite.
      Wahsaga hat Dir schon einen guten Tip gegeben, aber falls er Dir zu sehr in's Detail geht hier nochmal in der Übersicht:

      Dein Problem hast Du ja schon sehr gut erkannt.

      Was ich implementieren möchte ist eine funktion, um zwei Zeilen zu tauschen

      Du benötigst also etwas, das man im Programmiererbereich mit Englisch als Lingua Franca für gewöhnlich "Swapping" nennt. Getauscht wird genauso gewöhnlich mittels eines temporären Speichers.

      function swap(one,two){
        if(one && two){
          var temp;
          temp = one;
          one  = two;
          two  = temp;
          return true;
        }
        return false;
      }

      
      >   
      > Jetzt einfach einsetzen. "Einfach"? Ja, gut, aber \_so\_ schwer ist es auch nicht. Du mußt nur wissen, was genau Du austauschen möchtest. In Deinem Fall die Zeilen (Element "tr").  
      > Als Idee:  
      > ~~~javascript
        
      
      > function swapNodes(nodeOne, nodeTwo){  
      >   if(nodeOne && nodeTwo){  
      >     // Der Übersicht halber "Work on Copy".  
      >     // Aber wirklich _nur_ der Übersicht halber.  
      >     var copyOne  = document.getElementById(nodeOne);  
      >     var cloneOne = copyOne.cloneNode(true);  
      >   
      >     var copyTwo  = document.getElementById(nodeTwo);  
      >     var cloneTwo = copyTwo.cloneNode(true);  
      >   
      >     // Damit kann man jetzt oben beschriebenes Swapping  
      >     // ausführen.  
      >     copyOne.parentNode.replaceChild(cloneTwo, copyOne);  
      >     copyTwo.parentNode.replaceChild(cloneOne, copyTwo);  
      >   
      >     return true;  
      >   }  
      >   return false;  
      > }  
      > 
      
      

      Auf die Gefahr hin mich zu wiederholen: obiger Code dient ausschließlich pädagogischen Zwecken und kann bei unsachgemäßer Anwendung zu bleibenden Schäden führen. Dito bei sachgemäßer Anwendung.

      Aber ich hoffe das Prinzip ist soweit klar.

      so short

      Christoph Zurnieden

      1. Hi,

        danke für die Antwort.
        Zunächst ein paar Korrekturen, um Klarheit zu schaffen.

        1. Mein im ersten Posting angegebener Code hat nicht funktioniert, weil ...

        ... Deine Vorgehensweise nicht ganz dem Problem entspricht.

        Tja, ich mag Javascript schon aus diesem Grund einfach nicht, weil man es nicht zuverlässig debuggen kann.

        Da hatte ich noch nie Probleme, wo sind Deine? Kommst Du mit den gängigen Javascriptdebuggern nicht zurecht?

        1. Ich behaupte, dass _kein_ CallByReference, sondern CallByValue erfolgt.

        Du mußt zumindest beim Mozilla nichts behaupten sondern kannst in die Quellen schauen.

        Wenn CallByReference (wie von meinem Vorschreiber gesagt) verwendet würde, müsste ich Zeiger in meinem "Sicherungs-Array" haben. Das ist aber nicht der Fall, JavaScript speichert Objekte, und daher funktioniert es auch, die Objekte wieder einzufügen, obwohl sie ja vorher gelöscht wurden.

        Diese Kausalität kann ich nicht nachvollziehen. Bitte um nähere Erläuterungen.

        @Chritsoph:

        Auf die Gefahr hin mich zu wiederholen: obiger Code dient ausschließlich pädagogischen Zwecken und kann bei unsachgemäßer Anwendung zu bleibenden Schäden führen. Dito bei sachgemäßer Anwendung.

        Muss ich das verstehen? :-)

        Ja.

        Was ist eigentlich mit meinem Hinweis? Da Du mir geantwortet hast erwartete ich eigentlich auch ein wenig Kommentar zu meinem Vorschlag, fand jedoch nur Kommentare zu anderen Postings.

        so short

        Christoph Zurnieden