Stefan: Probleme mit importNode/replaceChild und XMLHttpRequest im IE

Hallo,

da ich in den Kopf einer Homepage einen kleinen Musik-Player einbauen möchte (Flash/Java), soll beim anklicken einer anderen Seite nun nicht alles neu geladen werden, sondern nur die Elemente mit dem Inhalt ausgewechselt werden.
Ich habe noch nie mit AJAX (XMLHttpRequest) gearbeitet (generell wenig mit JavaScript), aber dachte ich mir hier wäre es mal wirklich sinnvoll.

Ich habe es mir kurz angeschaut und in ungefähr einer halben Stunde habe ich folgenden in Firefox und Opera funktionierenden Code gebastelt:

var xmlHttp = null;
function dynstart()
{
 if(navigator.appName=="Microsoft Internet Explorer") {
  return;
 }
 if (typeof XMLHttpRequest != 'undefined') {
  xmlHttp = new XMLHttpRequest();
 }
 else return;
 if(xmlHttp == null) return;
 var menulinks = document.getElementById("menu").getElementsByTagName("a");
 for(var i=0; i<menulinks.length; i++) {
  menulinks[i].setAttribute("onclick", "openurl('"+menulinks[i].getAttribute("href")+"'); return false;");
 }
}
function openurl(url)
{
 xmlHttp.open('GET', url, true);
 xmlHttp.onreadystatechange =
  function () {
   if (xmlHttp.readyState == 4) {
    var body = document.getElementsByTagName("body")[0];
    var nnode = xmlHttp.responseXML.getElementById("main");
    body.replaceChild(document.importNode(nnode, true), document.getElementById("main"));
    nnode = xmlHttp.responseXML.getElementById("boxes_right");
    body.replaceChild(document.importNode(nnode, true), document.getElementById("boxes_right"));
   }
  };
 xmlHttp.send(null);
}

Der Code läuft einwandfrei in Opera 9 und Firefox 2, die Funktion dynstart(), die über onload vom body-element aufgerufen wird, fügt im Menü allen Links ein onclick-Attribut zur Funktion openurl(url) hinzu, welche einfach mit XMLHttpRequest die aufzurufende Seite lädt und dann zwei div-Elemente der alten durch die der neuen Seite ersetzt.

Ich habe dann über 2 Stunden gebastelt das im IE hinzukriegen, erfolglos. Andauernd kannte er Funktionen nicht (replaceChild, importNode) und ich habe keine Idee wie ich das hinkriegen soll.

Kann mir da jemand weiterhelfen?

Viele Grüße,
Stefan

  1. Hallo Stefan,

    Ich habe dann über 2 Stunden gebastelt das im IE hinzukriegen, erfolglos. Andauernd kannte er Funktionen nicht (replaceChild, importNode) und ich habe keine Idee wie ich das hinkriegen soll.

    replaceChild kann auch der IE, importNode soweit ich weiß jedoch nicht.

    Kann mir da jemand weiterhelfen?

    versuch es mal mit responseText und innerHTML.

    Gruß, Jürgen

    1. Hallo Jürgen,

      versuch es mal mit responseText und innerHTML.

      Danke für den Tipp mit innerHTML, es klappt jetzt mit outerHTML:

      var xmlHttp = null;
      function dynstart()
      {
       if (typeof XMLHttpRequest != 'undefined') {
        xmlHttp = new XMLHttpRequest();
       }
       if (!xmlHttp) {
        try {
         xmlHttp  = new ActiveXObject("Msxml2.XMLHTTP");
        } catch(e) {
         try {
          xmlHttp  = new ActiveXObject("Microsoft.XMLHTTP");
         } catch(e) {
          xmlHttp  = null;
         }
        }
       }
       if (!xmlHttp) return;
       var menulinks = document.getElementById("menu").getElementsByTagName("a");
       for (var i=0; i<menulinks.length; i++) {
        if (navigator.appName=="Microsoft Internet Explorer") menulinks[i].setAttribute("href", "javascript:openurl('"+menulinks[i].getAttribute("href")+"');");
        else menulinks[i].setAttribute("onclick", "openurl('"+menulinks[i].getAttribute("href")+"'); return false;");
       }
      }
      function openurl(url)
      {
       xmlHttp.open('GET', url, true);
       xmlHttp.setRequestHeader("Accept", "text/xml");
       xmlHttp.onreadystatechange =
        function () {
         if (xmlHttp.readyState == 4) {
          var body = document.getElementsByTagName("body")[0];
          if (navigator.appName=="Microsoft Internet Explorer") {
           var nnode = xmlHttp.responseXML.selectSingleNode("//div[@id='main']");
           document.getElementById("main").outerHTML = nnode.xml;
           nnode = xmlHttp.responseXML.selectSingleNode("//div[@id='boxes_right']");
           document.getElementById("boxes_right").outerHTML = nnode.xml;
          }
          else {
           var nnode = xmlHttp.responseXML.getElementById("main");
           body.replaceChild(document.importNode(nnode, true), document.getElementById("main"));
           nnode = xmlHttp.responseXML.getElementById("boxes_right");
           body.replaceChild(document.importNode(nnode, true), document.getElementById("boxes_right"));
          }
         }
        };
       xmlHttp.send(null);
      }

      Erfolgreich getestet mit Firefox 2, IE 6 und 7, Opera 9, Epiphany (Gecko 1.8.0), Konqueror 3.5, Safari (auf Windows).
      Opera 8 führt den Code richtig aus, rendert aber die neuen Elemente fehlerhaft (Hintergrund gibts nur hinter Text, sonst nicht).

      Viele Grüße,
      Stefan

      1. Hi,

        Opera 8 führt den Code richtig aus, rendert aber die neuen Elemente fehlerhaft (Hintergrund gibts nur hinter Text, sonst nicht).

        Evtl. hilft auch da mal wieder, ihm eins mit dem Zaunpfahl ueberzuziehen ...

        MfG ChrisB

        1. Hallo,

          Opera 8 führt den Code richtig aus, rendert aber die neuen Elemente fehlerhaft ...

          Opera 8 würde ich in der Hinsicht wie ein IE 5 behandeln: Links liegen lassen und nicht den barmherzigen Samariter mimen...

          (Aber selbst beim Opera 9 sind mir manche Rendering-Fehler noch aufgefallen. Reflow anstoßen ist aber nen sauübler Hack, den man ungerne einbauen will.)

          Mathias

          1. Hallo,

            ich habs mir nochmal angeschaut, die Rendering-Probleme sind noch etwas umfangreicher: Elemente haben auch zum Teil falsche Abmessungen und andere Elemente sind in Folge dessen nicht korrekt positioniert.
            Ich werde Opera 8 ignorieren, besonders das Opera Benutzer sich ja schon bewusst für einen anderen Browser entschieden haben und dann auch in der Lage sein sollten diesen zu aktualisieren. Auch zeigt die Statistik weniger als 0,2% der Besucher kamen mit Opera älter als 9.0 im Februar (bei knapp 5000 Besuchern (ohne Bots) und knapp 3% Opera insgesamt).
            Dafür muss ich nicht so einen großen Aufwand treiben.

            Viele Grüße,
            Stefan

            Zum Vergleich: Mit einem IE älter als 6.0 kamen rund 1% der Besucher.

  2. Hi,

    da ich in den Kopf einer Homepage einen kleinen Musik-Player einbauen möchte (Flash/Java), soll beim anklicken einer anderen Seite nun nicht alles neu geladen werden, sondern nur die Elemente mit dem Inhalt ausgewechselt werden.
    Ich habe noch nie mit AJAX (XMLHttpRequest) gearbeitet (generell wenig mit JavaScript), aber dachte ich mir hier wäre es mal wirklich sinnvoll.

    Nein, waere es m.E. nicht.

    Du versaust den normalen Aufbau einer Seite - unterschiedliche Links/URLs fuehren auf unterschiedliche Inhalte, die damit einzeln abrufbar, bookmarkbar, suchmaschinenverlinkbar, etc.-bar sind - nur um ununterbrochen dudeln zu koennen.

    Hier waere viel mehr ausnahmsweise mal der Einsatz eines Popups sinnvoll - darin kann der Flashplayer bis zum juengsten Tag dudeln (sofern er mag und ich als Nutzer ihn lasse) - und "darunter" kann dann auf einer ganz normalen Seite ganz normal navigiert werden, ohne jeglichen AJAX-Hype-Bullshit.

    MfG ChrisB

    1. Hi,

      ich bin auch eigentlich überhaupt kein Freund von sowas, aber Pop-Ups etc. mag ich noch weniger. Das tolle an meiner Lösung ist, sie ist komplett unabhängig: Ich erstelle meine Seiten ganz normal, die Links sind alle normal.
      Das bedeutet für Bots, User ohne (oder mir abgeschaltetem) JavaScript ändert sich nichts.
      Für welche mit JavaScript gibt es nun diese Ajax-Version _ohne_ das ich auch nur eine Seite doppelt mache oder in irgendeiner Form anpassen muss (natürlich muss sie sauberes XHTML sein, aber das mach ich sowiso). Finde ich genial. Auch sind die Ladezeiten (zumindest subjektiv) dramatisch gesunken, da die Seite nicht komplett neu gerendert wird.
      Man kann auch (außer im IE) noch problemlos neue Tabs/Fenster öffnen, da wird der Link geladen und nicht das JavaScript ausgeführt, bedeutet auch die Animation bleibt in der ersten Seite und existiert auf der zweiten gar nicht.
      Das einzige was mich ein bisschen stört, ist die Tatsache das die Vor/Zurück-Buttons nicht mehr funktionieren. Leider scheint es aus Sicherheitsgründen auch keine Möglichkeit zu geben JavaScript-Code einfach in die History-Liste einzutragen. Schade. Aber meine Seite ist auch ohne Vor/Zurück sehr gut zu navigieren.

      Viele Grüße,
      Stefan