dicon: JS/AJAX und DOM - style.display im IE 6 macht nicht was er soll

Moin community...

folgende Problemstellung:

unter diesem Link findet ihr den Anfang eines Projektes... http://www.embla.de/_lk76Z7hh55/

Bitte mal oben links einen Link klicken / ein Fenster öffnen. Im Fenster dann oben einen
Menüpunkt öffnen. Sowohl im FF als auch im IE (bei mir 6) klappt das Menü auf (zweite Menüebene
bitte ignorieren, soweit bin ich noch nicht.)

Ein erneuter klick auf den Menüpunkt sollte das ganze wieder schließen... wieder öffnen...
schließen... usw. FF alles fein. Im IE 6 bleib das Menü stehen - Warum?

Wie entsteht das Menü?... Während sich das Fenster öffnet wird via httpRequest die Menüzeile
durch ein PHP-Script (muss sein, da später alle Menüs/Submenüs aus einer MSQL dynamisch erstellt
werden) generiert und als Tabelle, die in ein neues DIV gekapselt ist, in die DOM-Struktur
eingebunden. Die Submenüs entstehen auf dem gleichen Weg.
Der Code für Menüs werden als komplette "Seite" eingebunden, beginnend mit <!DOCTYPE... und
endend mit </html>, alle externen CSS und JS sind entsprechend Deklaration enthalten.

Für das auf- und zuklappen der Menüs ist folgende JS-Funktion zuständig:

/* =========== snip begin =========== */

1 evtShowMenu = function(e){
2    var menu = getEventTarget(e);
3    var mId  = (e.target)? e.target.id : e.srcElement.id;
4
5    if(!mId) {
6       window.alert('Fehler - evtShowMenu: Event-Element nicht vorhanden.');
7    } else {
8      var m   = setMenuLev(mId);                   // erzeugt Id Folge-Menu
9      var isM = document.getElementById(m);        // ermittelt Folge-Menu
10
11      if (!isM) {                                  // prüft, ob Folge-Menu im DOM vorhanden
12          getAjaxData(mId);                        // wenn nein, erzeuge Folge-Menu
13      } else if (isM.style.display == 'none') {
14          isM.style.display = 'block';             // wenn ja und unsichtbar, mache sichtbar
15      } else if (isM.style.display == 'block') {
16          isM.style.display = 'none';              // wenn ja und sichtbar, mache unsichtbar
17          isM.style.border = 'solid 1px';          // nur zur Kontrolle für IE 6
18      } else {
19          window.alert('Fehler - evtShowMenu: Problem mit style.display .');
20      }
30   }
31 }

/* =========== snip end =========== */

Zeile 2 und 3: übernehmen das Eventobjekt vom Listener

Das Script läuft auch im IE 6 ohne Fehlermeldungen durch. Wenn Ihr das Menu schließt... öffnet,
schließt... seht ihr oben links neben dem Ausklapper eine dünne schwarze Linie (generiert in Zeile 17),
die tut was sie soll, nämlich erscheinen und verschwinden - nur eben der Ausklapper nicht.

Folgende Dinge habe ich ohne Ergebnis probiert:

a) Zeile 13 bis 18 in eine separate Funktion ausgelagert und durch window.setTimeout('func', 1000) ersetzt
   Hintergrund: vielleicht braucht der IE ja 'n bisschen, bis er versteht, was er machen soll

b) Zeile 13 bis 18 durch einen Funktionsaufruf ersetzt, der via removeChild das komplette Menü wieder
   aus dem DOM entfernt

c) document.all-Methode

Bleibt vielleicht noch zu erwähnen, dass es im IE 7 funktioniert. Leider muss ich bis IE 6 abwärtskompatibel
bleiben. Ich habe leider überhaupt keinen Plan, wo's klemmt - eventuell ja jemand von Euch

Vielleicht noch was: Ich beginne grad erst zu verstehen wie JS + DOM funktioniert und versuche es umzusetzen,
bewusst ohne auf fertige Sachen zurückzugreifen - etwas Nachsicht bitte, wenn der Code amateurhaft ist.

Grüße und Danke, dicon

  1. hi,

    9      var isM = document.getElementById(m);        // ermittelt Folge-Menu

    Ob isM hier wirklich auf das richtige Element verweist, hast du überprüft?

    13      } else if (isM.style.display == 'none') {
    14          isM.style.display = 'block';             // wenn ja und unsichtbar, mache sichtbar
    15      } else if (isM.style.display == 'block') {

    Und ob hier jeweils die Bedingung erfüllt ist, von der du es erwartest, hast du bereits überprüft?

    gruß,
    wahsaga

    --
    /voodoo.css:
    #GeorgeWBush { position:absolute; bottom:-6ft; }
    1. hallo wahsag

      jep alles geprüft... hab mir an jeder Stelle des Scriptes via window.alert() die entsprechende
      Elemente und Rückgabewerte auswerfen lassen... nach diesem Muster

      13      } else if (isM.style.display == 'none') {
      14          window.alert('evtShowMenu '+m+': - Menu vorhanden, aber nicht sichtbar, also werde sichtbar...');
      15          isM.style.display = 'block';             // wenn ja und unsichtbar, mache sichtbar
      16      } else if (isM.style.display == 'block') {
      17          window.alert('evtShowMenu '+m+': - Menu vorhanden und sichtbar, also werde unsichtbar...');
      18          isM.style.display = 'none';              // wenn ja und sichtbar, mache unsichtbar

      Die Varialble m steht für die DIV-ID des generierten Menü-DIVs.

      Via try {} catch(e) {} hab ich's auch probiert um event. "versteckte" Fehler abzufangen... naja, das Ergebnis
      ist bekannt...

      Für mich als Laien sieht es im IE irgendwie so aus, alsob das DIV mit dem Ausklapper irgendwie außerhalb der
      Struktur steht?!

      Vielleicht hilft die Funktion weiter, die das Menu-DIV generiert:

      203  function createMenu(menuId) {
      204     var toolbar = document.getElementById("toolbar");
      205     var menuPos = setMenuPos(menuId);
      206     var menu    = document.createElement("div");
      207     menu.style.position  = "absolute";
      208     menu.style.top       = menuPos.Y+"px";
      209     menu.style.left      = menuPos.X+"px";
      210     menu.style.display   = "block";
      211     menu.className       = "menu";
      212     menu.id              = menuPos.Id;
      213
      214     if(http.readyState == 4) {
      215        if (http.status == 200) {
      216            menu.innerHTML = http.responseText;
      217        } else {
      218            window.alert("Fehler");
      219        }
      220     }
      221
      222     toolbar.appendChild(menu);
      223  }

      Grüße, dicon

      1. hi,

        Für mich als Laien sieht es im IE irgendwie so aus, alsob das DIV mit dem Ausklapper irgendwie außerhalb der Struktur steht?!

        Das sollte sich ja bspw. mit der Developer Toolbar untersuchen lassen, wenn man mit der mal die DOM-Struktur unter die Lupe nimmt.

        gruß,
        wahsaga

        --
        /voodoo.css:
        #GeorgeWBush { position:absolute; bottom:-6ft; }
        1. Das sollte sich ja bspw. mit der Developer Toolbar untersuchen lassen, wenn man mit
          der mal die DOM-Struktur unter die Lupe nimmt.

          Das war der entscheidende Tip... wusste nicht, dass es für den IE was vergleichbares zu
          Firebug gibt... egal. Ich konnte den Fehler eingrenzen.

          Im IE 6 werden durch den httpRequest 5 DIVs erzeugt, alle mit indentischer ID, die ersten
          4 leer, das 5. dann mit dem eigentlichen HTML-Code für das Menü. Wenn ich jetzt versuche,
          mittels Event das Menu verschwinden zu lassen, spricht die Funktion evtShowMenu (s. oben)
          natürlich das erste Element mit der ID im DOM an und... es passiert "sichtbar" nix.

          Bleibt die Frage, was stimmt an dem httpRequest nicht. Für mich siehts so aus, alsob
          http.onreadystatechange vor dem empfangen der HTML-Daten auch den kompletten TCP-
          Handshake vorneweg verarbeitet und mit jeder Serverantwort (ACK, SYC usw.) ein DIV erzeugt.
          Nice to know... hilft mir aber nicht weiter.

          Vielleicht entdeckt ja jemand von Euch den Bug im httpRequest:

          /* =========== snip begin =========== */

          91     function getAjaxData(elementId) {
          92        http = false;
          93        url  = 'dyn_menu.php?ID='+elementId;
          94
          95        if (window.XMLHttpRequest) {
          96           http = new XMLHttpRequest();
          97           if (http.overrideMimeType) {
          98              http.overrideMimeType('text/xml');
          99           }
          100       } else if (window.ActiveXObject) {
          101          try {
          102             http = new ActiveXObject("Msxml2.XMLHTTP");
          103          } catch (e) {
          104             try {
          105                http = new ActiveXObject("Microsoft.XMLHTTP");
          106             } catch (e) {}
          107          }
          108       }
          109
          110       if (!http) {
          111          alert('Ende :( Kann keine XMLHTTP-Instanz erzeugen');
          112          return false;
          113       }
          114       http.open('GET', url, true);
          115       http.setRequestHeader( 'Content-length', url.length );
          116       http.onreadystatechange = new Function("createMenu('"+elementId+"')");
          117       http.send(null);
          118    }

          /* =========== snip end =========== */

          Vielleicht noch als Anmerkung: Ich hatte vor 'ner Zeit ein ähnliches Problem, allerdings
          mit der http.open POST Methode... damals lag's am Parameter "true" - mit "fals" war das
          Problem gelöst - wirkt aber im aktuellen Fall nicht.

          Grüße, dicon

          1. hi,

            Im IE 6 werden durch den httpRequest 5 DIVs erzeugt
            Bleibt die Frage, was stimmt an dem httpRequest nicht.
            Für mich siehts so aus, alsob http.onreadystatechange vor dem empfangen der HTML-Daten auch den kompletten TCP-
            Handshake vorneweg verarbeitet und mit jeder Serverantwort (ACK, SYC usw.) ein DIV erzeugt.

            onreadystatechange reagiert, wie der Name schon sagt, auf jeden "Change" des redayStates - und dieser durchläuft 5 Zustände:

            0 = uninitialized
            1 = loading
            2 = loaded
            3 = interactive
            4 = complete

            Und jedes mal rufst du deine Funktion createMenu auf.
            Die erzeugt jedes mal ein neues Div-Element.
            _Dann_ fragt sie ob, ob der readyState gleich 4 ist, und will irgendwas mit irgendeinem innerHTML machen.
            _Anschliessnd_ hängt sie, jetzt wieder vollkommen unabhängig vom aktuellen readyState, mit
            toolbar.appendChild(menu);
            das erzeugte Div-Element ins Dokument ein ...

            gruß,
            wahsaga

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

              Und jedes mal rufst du deine Funktion createMenu auf.

              ...

              Korrekt, daher war ich ja auch der Meinung, dass, wenn ich den http.open-Parameter "true/false" auf "false"
              setze, onreadystatechange erst abgearbeitet wird, wenn status == complete. Firefox versteht das, der
              IE 6 wohl nicht.

              Egal, ich hab das Problem erstmal gelöst, wobei ich nicht weiß, ob das 'ne wirklich elegante Lösung ist:

              Ansatz: Soll der Browser die Funktion createMenu doch sooft aufrufen wie er will... wichtig ist nur, dass
              das DIV mit dem Menü erst generiert wird, wenn readyState == 4/complete ist.

              Lösung: ich habe die komplette Generierung des DIVs innerhalb des if(http.readyState == 4)-Blocks gesetzt,
              vorher (s. weiter oben) stand dort ja nur innerHTML = http.responseText. Damit und dem Open-Parameter auf
              "true" funktioniert es mit den Menüs auch im IE.

              Jetzt habe ich eine andere Herausforderung - auch wieder nur für den IE. Die EventListener, die auf die
              Element im Menü zutreffen, reagieren im IE einfach nicht... aber auch das wird zu lösen sein... ;)

              Danke für die Hilfe / die Denkanstöße, dicon

              1. hi,

                Korrekt, daher war ich ja auch der Meinung, dass, wenn ich den http.open-Parameter "true/false" auf "false" setze,

                Du redest also von einem synchronen Request?

                onreadystatechange erst abgearbeitet wird, wenn status == complete.

                • dann benutzt man normalerweise überhaupt kein onreadystatechange, sondern führt die Verabreitung einfach sequentiell direkt nach dem Request aus.

                gruß,
                wahsaga

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