jonas99: Problem mit anzeigen von HTML-Code beim javascript

Moin Moin,

vorerst muss ich dazu sagen, dass ich in Javascript gerade nicht einmal richtige Grundkenntnisse habe, jedoch zu meinem Problem einiges gegoogelt habe. 😉

folgendes Problem habe ich: Ich habe eine MySQL Datenbank und ein PHP-Script, welcher die Daten aus der MySQL in eine xml Tabelle verfrachtet. Dann habe ich eine Google-Maps Karte erstellt, welche die Daten aus der xml-Tabelle zieht.

Jetzt habe ich das Problem, dass bei den Infoboxen (infoWindow) nur die HTML-Tags angezeigt werden, jedoch die Schrift nicht dementsprechend formatiert wird. In der Überschrift und dem footer(verweis auf Link), wo ich die HTML-Tags im Script selber geschrieben habe, funktioniert dies aber.

Hier mal ein paar Script-Auszüge:

var infoWindow = new google.maps.InfoWindow;

          
          downloadUrl('inc/map_bridge.php', function(data) {
            var xml = data.responseXML;
            var markers = xml.documentElement.getElementsByTagName('marker');
            Array.prototype.forEach.call(markers, function(markerElem) {
              var name = markerElem.getAttribute('name');
              var ide = markerElem.getAttribute('id');                            
              var desc = markerElem.getAttribute('beschreibung'); //deklarierung der Beschreibung aus xml Datei
              var type = markerElem.getAttribute('art');
                
              var us = '<b>ID ' + ide + ': ' + name + '</b><br><br>';
            var link = '<p>Klicke für weitere infos: <a href="http://link.de">Hier</a>';
              var point = new google.maps.LatLng(
                  parseFloat(markerElem.getAttribute('lat')),
                  parseFloat(markerElem.getAttribute('lng')));
            
             var contentString = us + desc + link; //zusammensetzung der Anzeige in der Infobox aus überschrift(us) + beschreibung (desc) + footer (link)

                    [...]

                marker.addListener('click', function() {
                infoWindow.setContent(contentString);
                infoWindow.open(map, marker);

Als Beispiel ein Eintrag aus der xml-Datei:

<markers>
<marker id="26" name="zweitertest" owner="test" lat="52.471158" lng="009.589752" art="Untergrund (Bunker, etc...)" zeit="2018-02-18 22:38:00" beschreibung="Zeile 1&lt;br&gt; Zeile 2\n Zeile 3 &lt;br&gt; Zeile 4"/>
</markers>

Und hier nochmal ein Screenshot des ganzen Problems:

Problembeschreibung

Ich hoffe, das eigentlich einfache Problem ausführlich beschrieben zu haben und eine Lösung zu finden. 😀

  1. Hallo,

    ich vermute, du musst die &lt; und &gt; in desc durch < und > ersetzen.

    Gruß
    Jürgen

    1. Hallo,

      das ist bei einer XML-Datei meines Wissens und Recherchen nach leider nicht möglich. Probiert habe ich es auch schon, aber dann ist bei der xml Datei die Beschreibung komplett leer.

      1. Hallo,

        du sollst die Korrekturen nicht in der xml-Datei durchführen, sondern vor dem Kopieren in das Infofenster.

        Gruß
        Jürgen

        1. lasse ich die Korrekturen in der xml-Datei bzw. bei der Erstellung der xml-Datei weg, bekomme ich einfach nur ein leeres ergebnis, da die xml-Datei Zeichen wie < und > nicht verträgt.

          <marker id="" name="" owner="" lat="" lng="" art="" zeit="" beschreibung=""/>
          
          1. Hallo,

            jetzt verstehe ich dein Problem nicht mehr. Dürfen in der XML-Datei &lt; und &gt; vorkommen?

            Gruß
            Jürgen

  2. Hallo jonas99,

    dein Problem ist - wie bei so vielen - der unsaubere Kontextwechsel.

    var us = '<b>ID ' + ide + ': ' + name + '</b><br><br>';
    var link = '<p>Klicke für weitere infos: <a href="http://link.de">Hier</a>';
    var point = new google.maps.LatLng(...);
    
    var contentString = us +        // Hier steht HTML
                        desc +      // Hier steht maskiertes HTML
                        link;       // Hier steht HTML
    

    Problem ist nun, dass es nicht mal eben so eine Javascript-Funktion zu geben scheint, die die Entity-codierung in desc rückübersetzt.

    Ich sehe zwei Wege, das zu umschiffen. Wenn es nur um Zeilenumbrüche geht, kannst Du Dir ein eigenes Zeichen (oder eine Zeichenfolge) ausdenken, die für einen Umbruch steht. Die ersetzt Du dann mittels split und join durch <br>.

    Wenn Du mehr brauchst, also HTML-Elemente in der Description, dann könntest Du den alternativen Input für setContent verwenden: einen Node. Den baust Du on-the-fly zusammen.

    (...)
    var desc = markerElem.getAttribute('beschreibung');
    (...)
    var contentString = us + '<span class="innerInfoText"></span>' + link;
    
    (...)
    
    marker.addListener('click', function() {
       var infoContent = document.createElement("div");
       infoContent.innerHTML = contentString;
       infoContent.querySelector(".innerInfoText").innerHTML = desc;
    
       infoWindow.setContent(infoContent);
       infoWindow.open(map, marker);
    };
    

    Mit createElement erzeugst Du ein div-Element, erstmal im leeren Raum. Dem gibst Du dann ein HTML-Innenleben, ähnlich dem HTML dass Du vorher dem InfoWindow gegeben hast, aber mit einem Platzhalter für den desc Teil. Dieser Platzhalter ist ein span-Element mit einer Klasse; dieses Element suchst Du dann mit querySelector heraus und gibt ihm wiederum ein HTML Innenleben. Damit hast Du den Kontext gewahrt und das Fenster müsste sauber erscheinen.

    Natürlich ist das riskant. Du musst sicherstellen, dass der desc-String vertrauenswürdig ist. Er darf nicht von einem Dir unbekannten User eingegeben sein. Andernfalls könnte er Script-Elemente enthalten, die Böses tun.

    Übrigens war in deinem Code vermutlich ein Kopierfehler: der Click-Handler sollte an markerElem angehängt werden, oder?

    Unabhängig von der verwendeten Variante noch eine Überlegung. Wenn Du sie nicht verstehst, ignoriere sie einfach, vermutlich ist es nicht wirklich gravierend.

    Ob dein Vorgehen von der Variablenhaltung her optimal ist, da bin ich nicht sicher. Du baust hier einiges an Closures zusammen, bei vielen Markern kann das einiges an Speicher fressen. Mit der Effizienz von Closures in JavaScript bin ich nicht 100% vertraut; es mag auch von Browser zu Browser verschieden sein. Ich würde vermutlich das Anhängen des Event-Listeners in eine Funktion auslagern, die möglichst global aufgehängt ist (um möglichst wenige geschachtelte Closures zu erben), und ihr map, markerElem, contentString und desc als Parameter übergeben. Die Closure um den Eventhandler ist dann viel kleiner.

    Ach ja. Was ist eine Closure. Hier steht etwas dazu. Die Kurzfassung ist: wenn Du den Eventhandler inline im Ajax-Responsehandler definierst, bekommt er den aktuellen Variablensatz des Responsehandlers als Anhängsel mit und die Variablen werden nach Ende des Responsehandlers nicht freigegeben.

    Rolf

    --
    sumpsi - posui - clusi