Matze: Javascript läßt sich nicht auslagern - reloaded

problematische Seite

So, wie angedroht bin ich jetzt mit einem Account angemeldet und werde meine Frage jetzt erweitern....

Doch zuerst einmal der Code um den es mir geht:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
 <!--  <script src="boxentest.js"></script>  -->
  <meta name="viewport" content="width=device-width">
  <title>Test</title>
</head>
<body>

   <label for="farbe01">Rand: </label>
   <input type="checkbox" id="s1" value="Rand">
			<input id="farbe01" type="color" value="#466eaf">
			<output id="ausgabe01"></output>
			<br>
   <label for="farbe02">Schatten: </label>
   <input type="checkbox" id="s2" value="schatten">
			<input id="farbe02" type="color" value="#006767">
			<output id="ausgabe02"></output>
			<br>
   <label for="farbe03">Steg: </label>
   <input type="checkbox" id="s3" value="steg">
			<input id="farbe03" type="color" value="#00ff00">
			<output id="ausgabe03"></output>
			<br><br><br>	
			  
  <p id="box1" aria-live="polite"></p>
  <p id="box2" aria-live="polite"></p>
  <p id="box3" aria-live="polite"></p>  
			
<script>
 window.addEventListener('DOMContentLoaded', function () {window.addEventListener("load", farbwahl00);
 document.getElementById("farbe01").addEventListener("change", farbwahl00);
 document.getElementById("farbe02").addEventListener("change", farbwahl00);
 document.getElementById("farbe03").addEventListener("change", farbwahl00);
	function farbwahl00() {
  	    const farbe01= document.getElementById("farbe01").value;
        const farbe02= document.getElementById("farbe02").value;
		const farbe03= document.getElementById("farbe03").value;	
        document.getElementById("ausgabe01").textContent = farbe01;
	    document.getElementById("ausgabe02").textContent = farbe02;
	    document.getElementById("ausgabe03").textContent = farbe03;}
});

const box02 = [
  {"checkboxID": "s1",
    "checked": "Rand ist aktiviert!",
    "outputID": "box1",
    "unchecked": ""},
  {"checkboxID": "s2",
    "checked": "Schatten ist aktiviert!",
    "outputID": "box2",
    "unchecked": ""},
  {"checkboxID": "s3",
    "checked": "Steg ist aktiviert!",
    "outputID": "box3",
    "unchecked": ""}
];

document.body.addEventListener("input", event => {
  box02.forEach(data => {
    const
      checkbox = document.getElementById(data.checkboxID),
      output = document.getElementById(data.outputID);

    if (checkbox && output && event.target == checkbox) {
      output.textContent = checkbox.checked ? data.checked : data.unchecked;
    }
  });
});
</script>

</body>

Hierzu habe ich mehrere Fragen (Herausforderungen).

  1. Wenn ich den Scriptteil in die boxentest.js auslagere (ja, ist in diesem Beispiel auskommentiert, das weiß ich!)) aktualisiert er mir in der Anzeige zwar die Farbwerte aber Er zeigt nicht mehr an welches Element 'aktiviert' ist. Kann das daran liegen, dass ich in den unteren EventListener (box02) noch keinen 'DOMContentLoaded' gesetzt habe und wenn ja, wie füge ich den ein?

  2. Bezieht sich auch auf den unteren Eventlistener (box02). Macht hier ein 'input', daß sich auf den 'body' bezieht wirklich Sinn? Da ich ja weitere Funktionen einbaue ist es glaube ich nicht gut, sich nur für diese auf den Body zu beziehen. Wäre es also nicht klüger auch hier ein 'getElementById' mit 'change' zu setzen? Aber was setze ich dann als Auslöser (data.checkboxID), (box02) oder gibt es da etwas was ich übersehen habe?

  3. Gibt es eine Möglichkeit...... äehm... die in der ersten Funktion bestimmten Variablen (farbe01 - farbe03) mit der ausgabe der zweiten Funktion zu verknüpfen? Hinter dem 'Rand ist aktiviert' steht dann der Farbwert von farbe01, hinter dem 'Schatten ist aktiviert' steht dann der Wert von farbe02..... usw

  4. Eher unwichtig, könnte mir aber die zukünftige Arbeit an meinem Projekt erleichtern. In der ersten Funktion (farbwahl00) wiederhole ich auch sehr oft den selben code was ja nicht sehr 'Dry' ist wie ich gelernt habe - Kann ich auch da irgendwie ein Array einarbeiten.....

Ich habe mal zwei Links eingefügt..... Einen zur eigentlichen Seite Das ist aber im Moment eher ein grober Entwurf - zeigt aber in der verlinkten Unterseite wo ich mal hin will wenn ich groß bin. Der zweite link ist einfach nur ein Testaufbau der wieder verschwindet wenn meine Fragen beantwortet sind..... Die Ladezeiten können bei beiden etwas länger sein, weil der Server hier vor mir auf dem Küchentisch steht.

Danke schon mal im vorraus für alle Tips und Anregungen, aber denkt daran - Bitte Langsam sprechen ich habe grade erst angefangen JS zu lernen.

Okay, bis dann,

Matze

akzeptierte Antworten

  1. problematische Seite

    Lieber Matze,

    Doch zuerst einmal der Code um den es mir geht:

    den braucht es nicht, da Du ein Online-Beispiel bereitgestellt hast, welches man unter „problematische Seite“ bequem erreichen und untersuchen kann. So bin ich auch auf die Datei boxentest.js gestoßen.

    Kann das daran liegen, dass ich in den unteren EventListener (box02) noch keinen 'DOMContentLoaded' gesetzt habe und wenn ja, wie füge ich den ein?

    In boxentest.js ist nur ein Teil der Geschäftslogik in den DOMContentLoaded-EventListener eingebunden. Du könntest grundsätzlich alles dort hineinschreiben. Ob das aber das Problem löst, kann ich aktuell nicht sagen.

    Wenn ein input-Event den Body erreicht, muss die passende EventListener-Funktion starten, sich aus dem Array alle Zusammenhänge holen und der Reihe nach abarbeiten. Das sollte auch funktionieren, wenn Du den EventListener nicht innerhalb der DOMContentLoaded-Funktion an den Body bindest, denn der Body ist grundsätzlich immer da. Es sei denn, dieser würde später nach dem Parsing durch ein anderes Objekt ersetzt, was aber keinen Sinn ergibt.

    Macht hier ein 'input', daß sich auf den 'body' bezieht wirklich Sinn?

    Ja, das tut es. Ereignisse werden von einem Element aus ausgelöst. Dann fangen sie an zu „blubbern“, sodass irgendwann der Body dieses Event abbekommt. Genau hier greift dann unsere Funktion, die ihrerseits das ursprünglich auslösende Element ermittelt, das in event.target referenziert ist.

    Da ich ja weitere Funktionen einbaue ist es glaube ich nicht gut, sich nur für diese auf den Body zu beziehen. Wäre es also nicht klüger auch hier ein 'getElementById' mit 'change' zu setzen? Aber was setze ich dann als Auslöser (data.checkboxID), (box02) oder gibt es da etwas was ich übersehen habe?

    Die Idee ist, genau eine Funktion über das Event auslösen zu lassen, die dann ihrerseits klärt, was zu tun ist. Du kannst verschiedene Funktionalitäten von dieser einen Funktion aus steuern. Kommt darauf an, was Du wirklich zu erreichen suchst.

    1. Gibt es eine Möglichkeit...... äehm... die in der ersten Funktion bestimmten Variablen (farbe01 - farbe03) mit der ausgabe der zweiten Funktion zu verknüpfen? Hinter dem 'Rand ist aktiviert' steht dann der Farbwert von farbe01, hinter dem 'Schatten ist aktiviert' steht dann der Wert von farbe02..... usw

    Ja. Was spricht denn dagegen, das passende Farbwahl-Element (oder vielmehr dessen ID) in das jeweilige Zusammenhänge-Objekt aufzunehmen?

    const tasks = [
      {
        "checkboxID": "s1",
        "checked": "Rand ist aktiviert!",
        "colorID": "farbe1",
        "outputID": "box1",
        "unchecked": ""
      }
    ];
    

    In der Auswertung wird dann eben dessen Wert berücksichtigt:

      tasks.forEach(data => {
        const
          checkbox = document.getElementById(data.checkboxID),
          colorChooser = document.getElementById(data.colorID),
          output = document.getElementById(data.outputID);
    
        if (checkbox && output && event.target == checkbox) {
          let text = checkbox.checked ? data.checked : data.unchecked;
    
          if (colorChooser) {
            text += " - Farbe: " + colorChooser.value;
          }
    
          output.textContent = text;
        }
      });
    
    1. Eher unwichtig, könnte mir aber die zukünftige Arbeit an meinem Projekt erleichtern. In der ersten Funktion (farbwahl00) wiederhole ich auch sehr oft den selben code was ja nicht sehr 'Dry' ist wie ich gelernt habe - Kann ich auch da irgendwie ein Array einarbeiten.....

    LOL - siehe oben. ;-) Deshalb nannte ich das Array ursprünglich auch nicht box02, sondern tasks, weil ich davon ausging, dass man damit noch mehr tun kann, als nur eine bestimmte Box zu überwachen.

    Liebe Grüße

    Felix Riesterer

    1. problematische Seite

      ......In boxentest.js ist nur ein Teil der Geschäftslogik in den DOMContentLoaded-EventListener eingebunden. Du könntest grundsätzlich alles dort hineinschreiben. Ob das aber das Problem löst, kann ich aktuell nicht sagen.

      Haha, ich hab jetzt echt grade gedacht Du meinst in jede JS-Datei kann man nur ein DOMContentLoaded packen..... Muhaha! Der war gut!

      Oder meinst Du das ernst? ..... Mist, Ich hab alles falsch verstanden!

      Puh! Danke für die schnelle umfassende Antwort. Ich werd das jetzt erstmal alles lesen, wenn ich es dann richtig verstanden habe werde ich versuchen das umzusetzen, Weinen und weitere Fragen formulieren!

      Aber soweit.... echt Danke!

      MFG Matze

      1. problematische Seite

        Hallo Matze,

        mit addEventListener kannst Du für jedes Event beliebig viele EventListener registrieren. Ausgeführt werden sie in Reihenfolge der Registrierung. Also, ja, der war gut 😉

        Eine DOMContentLoaded-Steuerung brauchst Du dann und nur dann, wenn dein Script ausgeführt wird, bevor die darin angesprochenen DOM-Elemente existieren. Also dann, wenn das Script im <head> oder zu Beginn des <body> läuft.

        Wenn es Dir zu unübersichtlich ist, deinen ganzen Code in einen DOMContentLoaded-Handler zu packen, dann kannst Du den Code auch in eine eigene Funktion schreiben, oder mehrere Funktionen, und als DOMContentLoaded-Handler eine kleine Funktion einsetzen, die deine eigenen Funktionen aufruft.

        Es gibt aber auch Alternativen:

        • das Script am Ende des <body> einbinden (dann wird erst das DOM aufgebaut und danach das Script geladen) - der Browser wartet eh mit der ersten Layout-Runde, bis die synchronen Scripte fertig sind.
        • Dem script-Element das Attribut defer geben - solche Scripte werden asynchron geladen. Just bevor DOMContentLoaded ausgelöst wird, ist der Synchronisierungspunkt. Der Browser wartet an dieser Stelle, bis alle mit defer geladenen Scripte bereit sind, führt sie DANN aus und signalisiert DANN DOMContentLoaded.
        • Dem script-Element das Attribut type="module" geben. Für solche Module ist das defer-Attribut implizit gesetzt. Damit ändert sich allerdings auch ein bisschen die Art, wie das Script ausgeführt wird; ECMAScript-Module laufen grundsätzlich im Strict Mode und die globalen Variablen, die man darin definiert, sind in ihrer Sichtbarkeit auf das Script begrenzt.

        Das async-Attribut gibt es auch, aber async-Scripte starten, sobald sie geladen sind. Ob das DOM schon fertig ist, weiß man nicht. Und der Browser wartet auch nicht auf async-Scripte, bevor er die Seite anzeigt.

        Rolf

        --
        sumpsi - posui - obstruxi