suit: "Speicherort" für JavaScript-Konfiguration

Hallo,

ich hab' ein recht umfangreiches JavaScript, welches mittels der Google Maps API V3 eine (künftig mehrere) Karte(n) erzeugt.

Die Konfiguration ist eine Variable (JSON) die das Script durchläuft und sich dort die Konfiguration und die Standorte rausholt.

Aktuell wird die Variable in einem script-Element ausgegeben:

<script>  
  var config = // JSON Dinges  
</script>

Dort steht dann unter anderem in welchem Element die Karte eigentlich eingefügt werden soll (bzw. welches sie ersetzen soll) - alternativ wird dort aber auch der Fallback-Inhalt ausgegeben, der dann mit der Karte ersetzt wird.

Jetzt soll die Karte mehrfach (mit unterschiedlicher Konfiguration und an unterschiedlichen Stellen im Quelltext) erstellt werden können - das funktioniert theoretisch auch einwandfrei - das Problem ist die Konfiguration selbst.

Erster Ansatz ist, dass ein Array/Objekt dazwischenziehe - also

<script>  
  var config.id277 = // JSON Dinges  
</script>

und an anderer Stelle:

<script>  
  var config.id123 = // JSON Dinges  
</script>

Hier muss[sic?] ich allerdings vorher prüfen, ob config.id277 bereits ein Array/Objekt ist (bzw. umgekehrt, obs undefined ist und falls das der Fall ist, eben ein Array erstellen).

Das führt dazu, dass das halt so aussieht:

  if (typeof config == 'undefined') {  
    var config = new Array();  
  }  
  config.id123 = 'foo';

Das config-Array/Objekt kann ich im Anschluss durchlaufen und alle zu erzeugenden Karten abarbeiten.

Die Alternative wäre die JSON-Konfiguration eine "Datenquelle" zu schreiben, die im Dokument steht und "nichts" tut, außer schön auszusehen:

<script data-maps-config="{foo}"></script>
In HTML5 ist das kein Problem, sieht aber etwas komisch aus - funktioniert aber soweit ich das beurteilen kann einwandfrei.

Vorschläge, Anregungen, Wünsche, Beschwerden?

  1. Hallo,

    Das führt dazu, dass das halt so aussieht:

    if (typeof config == 'undefined') {

    var config = new Array();
      }
      config.id123 = 'foo';

      
    <http://stackoverflow.com/questions/2703102/typeof-undefined-vs-null>  
    darin: "If the variable is declared (either with the var keyword, as a function argument, or as a global variable), I think the best way to do it is:  
      
    if (my\_variable === undefined)  
      
    jQuery does it, so it's good enough for me :-)"  
      
    Also die zwei Gleichheitszeichen bergen u.U. Überraschungen.  
      
    Ansonsten verstehe ich Dein Problem nicht. Du kannst doch Dein Objekt deklarieren. Oder Du übergibst Deine Werte einer Funktion, die am Ende ein gewünschtes Objekt erstellt.  
      
    sinngemäß:  
    ObjectCreator.collect();  
    irgendwo im Code.  
      
    myObj = ObjectCreator.create();  
    am Ende.  
      
    Gruß  
      
    jobo
    
    1. if (my_variable === undefined)

      jQuery does it, so it's good enough for me :-)"

      Also die zwei Gleichheitszeichen bergen u.U. Überraschungen.

      Sounds legit - das hab' ich gleich ersetzt.

      Ansonsten verstehe ich Dein Problem nicht. Du kannst doch Dein Objekt deklarieren.

      Das JSON-Objekt enthält nur die Konfiguration in Form von einfacher Variablen (Strings, Zahlen, boolsche Werte).

      Oder Du übergibst Deine Werte einer Funktion, die am Ende ein gewünschtes Objekt erstellt.

      Ja.

      sinngemäß:
      ObjectCreator.collect();
      irgendwo im Code.

      myObj = ObjectCreator.create();
      am Ende.

      Das geht nicht, weil die Klasse zu diesem Zeitpunkt noch garnicht existiert - die eigentliche Funktionalität wird aus performancegründen ganz am Ende eingebunden (vor dem schließenden body-Tag).

      Drum muss eine Lösung her, wo ich im Dokument (für JavaScript lesbare) Daten abglege die ich am Schluss geordnet lesen kann. Die Daten ebenfalls erst am Ende des Dokuments zu hinterlegen ist leider keine Option.

      1. Hallo,

        Das geht nicht, weil die Klasse zu diesem Zeitpunkt noch garnicht existiert - die eigentliche Funktionalität wird aus performancegründen ganz am Ende eingebunden (vor dem schließenden body-Tag).

        am Anfang des Dokumnents kannst Du doch aber ein Objekt erstellen.

          
        ConfigHander = {  
            collectedStuff : {},  
            getConfig : function () {  
                return this.CollectedStuff;  
            },  
            addConfigStuff : function (stuffToAdd) {  
                //do whatever you have to to  
                    var id = 123;  
                    var tmpObj = transform(stuffToAdd);  
                    this.collectedStuff[id] = tmpObj;  
            }  
        }  
        
        

        ungetestet.

        Drum muss eine Lösung her, wo ich im Dokument (für JavaScript lesbare) Daten abglege die ich am Schluss geordnet lesen kann. Die Daten ebenfalls erst am Ende des Dokuments zu hinterlegen ist leider keine Option.

        Aha, warum nicht. Aber vielleicht bereits am Anfang?

        Gruß

        jobo

        1. am Anfang des Dokumnents kannst Du doch aber ein Objekt erstellen.

          Nein, am Anfang des Dokuments gibts kein JavaScript :)

          Ich verstehe deinen Ansatz - aber der Sinn hinter dieser Sache ist, so viel Funktionalität wie möglich ans Ende des Dokuments zu verfrachten - und alles was zuvor schon drin steht, soll auf das wesentliche reduziert sein.

          Drum muss eine Lösung her, wo ich im Dokument (für JavaScript lesbare) Daten abglege die ich am Schluss geordnet lesen kann. Die Daten ebenfalls erst am Ende des Dokuments zu hinterlegen ist leider keine Option.

          Aha, warum nicht.

          Es ist eine TYPO3-Extension die zwar zur Laufzeit super Inhalte generieren kann, aber nicht an beliebigen stellen im Dokument sondern eben nur "da" wo sie ist - und ins "mitgelieferte" zusammengefasste Default-JavaScript reinschreiben kann ich nicht, weil das (weil es viel Mist enthält) ganz einfach deaktiviert ist :)

          Aber vielleicht bereits am Anfang?

          Das einzige was "bereits am Anfang" eingebunden wird, ist ein 1-Zeiler der eine Klasse ins html-Element packt, wenn JavaScript prinzipiell vorhanden ist :)

          1. Hallo,

            Das einzige was "bereits am Anfang" eingebunden wird, ist ein 1-Zeiler der eine Klasse ins html-Element packt, wenn JavaScript prinzipiell vorhanden ist

            Aha, und eine Script-Element im Head geht nicht? Oder gleich am Anfang des body?

            Gruß

            jobo

            1. Das einzige was "bereits am Anfang" eingebunden wird, ist ein 1-Zeiler der eine Klasse ins html-Element packt, wenn JavaScript prinzipiell vorhanden ist

              Aha, und eine Script-Element im Head geht nicht? Oder gleich am Anfang des body?

              "Geht nicht" ist eine Designentscheidung, weil eben so wenig wie möglich an Scripten "früh" im DOM stehen soll.

              1. Hallo,

                Das einzige was "bereits am Anfang" eingebunden wird, ist ein 1-Zeiler der eine Klasse ins html-Element packt, wenn JavaScript prinzipiell vorhanden ist

                Aha, und eine Script-Element im Head geht nicht? Oder gleich am Anfang des body?

                "Geht nicht" ist eine Designentscheidung, weil eben so wenig wie möglich an Scripten "früh" im DOM stehen soll.

                Nun ja, wenn du dafür lieber jedes Mal checken willst, ob ein JSObjekt existiert. Wenn Du eins brauchst, solltest Du es schon zu Beginn initialisieren ;-). Denn es heißt ja: so wenig wie _möglich_.

                Ansonsten kann du auch JSON irgendwo mit display:none zusammen reinschreiben oder in ein hidden-input-Feld und das am Ende mit eval zu einem Objekt machen.

                Gruß

                jobo

                1. Ansonsten kann du auch JSON irgendwo mit display:none zusammen reinschreiben oder in ein hidden-input-Feld und das am Ende mit eval zu einem Objekt machen.

                  Da dann doch lieber der HTML5-Data-Attribut.

                  1. Hi,

                    Da dann doch lieber der HTML5-Data-Attribut.

                    Das muss ja aber im Gegensatz zu deinem Beispiel nicht an einem Script-Element untergebracht sein.

                    MfG ChrisB

                    --
                    RGB is totally confusing - I mean, at least #C0FFEE should be brown, right?
                    1. Da dann doch lieber der HTML5-Data-Attribut.

                      Das muss ja aber im Gegensatz zu deinem Beispiel nicht an einem Script-Element untergebracht sein.

                      Ja, das ist mir klar - aber es gibt an dieser Stelle kein Element, welches da sein wird (zumindest nicht immer).

                      Es gibt zwar Varianten wo eine Liste an Adressen ausgegeben wird, die dann durch Karte ersetzt werden - da ist es einfach

                      <ul data-map-config="hier">  
                        <li>adresse 1</li>  
                        ...  
                      </ul>
                      

                      Gerne liegen hier auch die einzelnen Positionsinformationen in den li-Elementen - aber es kommt auch oft genug vor, dass einfach gesagt wird "mach die Karte mal irgendwo hin, nur nicht gerade an dieser Stelle" :)

                      Irgend ein "ich bin nur Daten die einfach in der Landschaft rumstehen"-Element in HTML5 ist mir nicht bekannt - vielleicht ein leeres span-Element?

                  2. Hallo,

                    Ansonsten kann du auch JSON irgendwo mit display:none zusammen reinschreiben oder in ein hidden-input-Feld und das am Ende mit eval zu einem Objekt machen.

                    Da dann doch lieber der HTML5-Data-Attribut.

                    Naja, wenn du weißt, in welches Elementen es steckt oder aber Du aber mit einer Bibliothek wie jquery auf alle Elemente mit einem bestimmten Attribut zugreifen kannst. Der stringenteste Weg scheint mir aber, ein Objekt zu Beginn zu initialisieren/deklarieren, in das dann mit Script-Elementen die in Frage kommenden Daten eingetragen werden ...;

                    Gruß

                    jobo

  2. Hallo,

    Das führt dazu, dass das halt so aussieht:

    if (typeof config == 'undefined') {

    var config = new Array();
      }
      config.id123 = 'foo';

      
    Erstens suchst du hier ein einfaches Objekt, also new Object() oder einfach {}.  
    Arrays sind auch Objekte, also kannst du ihnen auch Eigenschaften anhängen, was du hier tust. Das gilt aber genauso für, sagen wie, Date und RegExp. <http://de.selfhtml.org/javascript/objekte/array.htm#assoziative_arrays@title=Assoziative Arrays> gibt es in JavaScript nicht. Die wirkliche Funktionalität von Arrays nutzt du hier aber nicht. Arrays haben immer numerische Indizes. Dedizierte Hashes gibt es in JavaScript nicht, dafür gibt es Object. Die kannst du mit for-in anstelle einer normalen for-Schleife durchlaufen. Ein Object hat im Gegensatz zu einem Array keine »length«.  
      
    Zweitens, ja, so könnte es aussehen. Ist das schlimm? Ist das problematisch? Erfüllt das nicht den Zweck? Wieso fragst du? ;)  
      
    Mathias
    
    1. Zweitens, ja, so könnte es aussehen. Ist das schlimm? Ist das problematisch? Erfüllt das nicht den Zweck? Wieso fragst du? ;)

      Es erfüllt seinen Zweck ja - aber da mein JavaScript-Wissen nicht so ins Detail geht, schadet eine Nachfrage nicht. Möglicherweise übersehe ich ja irgendetwas schlaues.

  3. var config = config || {};
    config.var = 'foo';

    Schöner fände ich aber auch Fallbackcontainer mit "data-"-Attributen, die per JS im Body unsichtbar geschaltet und bei domReady ausgelesen werden.

    1. Hallo,

      var config = config || {};
      config.var = 'foo';

      Aber doch nur einmal am Anfang, oder? Ein leeres Objekt ist doch keine Last.

      Schöner fände ich aber auch Fallbackcontainer mit "data-"-Attributen,

      Was sind denn Fallbackcontainer?

      die per JS im Body unsichtbar geschaltet

      Aber warum per JS? Die sollen doch sowieso nie sichtbar sein. Warum kein <input type=hidden>?

      und bei domReady ausgelesen werden.

      Warum nicht bei window.onload? Oder reicht das nicht unten im Dokument kurz vor dem schließenden body-Tag?

      Gruß

      jobo

      1. Schöner fände ich aber auch Fallbackcontainer mit "data-"-Attributen,

        Was sind denn Fallbackcontainer?

        Diese Lösung hier, geht aber nicht, weil es nicht immer einen Fallback-Inhalt gibt.

        die per JS im Body unsichtbar geschaltet
        Aber warum per JS? Die sollen doch sowieso nie sichtbar sein.

        Doch, wenn kein JavaScript da ist und die Karte nicht angezeigt wird, soll der Fallback-Inhalt sehrwohl sichtbar sein (das ist der Sinn davon).

        Warum kein <input type=hidden>?

        Weil input-Elemente dafür nicht geeignet sind, dafür gibts data-Attribute.

        und bei domReady ausgelesen werden.

        Warum nicht bei window.onload?

        Weil das load-Event wesentlich später feuert als das fertigstellen des DOM - es gibt keinen Grund, so lange zu warten :)

        Oder reicht das nicht unten im Dokument kurz vor dem schließenden body-Tag?

        Prinzipiell ja - ready ist aber schöner