Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. Skript im VIS-2 Editor funktioniert nur im Editor

    NEWS

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    Skript im VIS-2 Editor funktioniert nur im Editor

    This topic has been deleted. Only users with topic management privileges can see it.
    • V
      Vippis last edited by

      Hallo liebe Community,

      ich möchte mit einem HTML Widget ein interaktives Dropdown Menü erstellen, wo der Nutzer einzelne Messwerte auswählen kann und die Auswahl in einem Datenpunkt gespeichert wird. Anschließend soll er auf "Auswerten" klicken können, dann werden die gewählten Messdaten aus der InfluxDB im gewählten Zeitraum gefischt und in einer CSV zum Download bereitgestellt.

      Die verfügbaren Messwerte liegen auch in einem Datenpunkt, die zuvor ein Crawler Skript erstellt hat.

      Mein Problem ist jetzt, dass der Javascript Code, der das Dropdown-Menü befüllen soll, nur im Editor der VIS-2 funktioniert im Runtime Modus, aber nicht im Browser (Firefox und Chrome geht beides nicht, sowie die IOBroker App auf iOS auch nicht).

      Woran kann das liegen?

      HTML-Widget:

      <div id="dropdown-container" style="position: relative; display: inline-block; width: 200px;">
          <!-- Button für das Dropdown -->
          <div id="dropdown-toggle" class="btn_grafana_style" style="position: relative; display: flex; align-items: center; justify-content: space-between; padding: 10px; cursor: pointer;">
              <span>Messwerte auswählen</span>
              <!-- Pfeil-Symbol -->
              <span id="dropdown-arrow" style="margin-left: 10px; font-size: 12px;">▼</span>
          </div>
      
          <!-- Dropdown-Menü -->
          <div id="dropdown-menu" style="position: absolute; top: 100%; left: 0; width: 100%; background-color: white; border: 1px solid #ccc; padding: 10px; z-index: 1000; max-height: 300px; overflow-y: auto; display: none;">
              <!-- Hier werden die Checkboxen dynamisch hinzugefügt -->
          </div>
      </div>
      
      

      Javascript Code im Bereich "Skripte" im VIS Editor:

      // IDs der Datenpunkte
      const sourceDataPoint = "0_userdata.0.Export.Verfügbare_Messwerte"; // JSON mit Messwerten
      const targetDataPoint = "0_userdata.0.Export.Ausgewählte_Messwerte"; // Array für ausgewählte Messwerte
      
      // Dropdown-Elemente
      const dropdownToggle = document.getElementById("dropdown-toggle");
      const dropdownMenu = document.getElementById("dropdown-menu");
      
      // Funktion: Dropdown anzeigen/verstecken
      dropdownToggle.addEventListener("click", (event) => {
          event.stopPropagation(); // Verhindert, dass der Klick das Schließen triggert
          dropdownMenu.style.display = dropdownMenu.style.display === "none" ? "block" : "none";
      });
      
      // Funktion: Schließt das Dropdown, wenn man außerhalb klickt
      document.addEventListener("click", (event) => {
          if (!dropdownMenu.contains(event.target) && event.target !== dropdownToggle) {
              dropdownMenu.style.display = "none";
          }
      });
      
      // Funktion: Verfügbare Messwerte laden und Checkboxen generieren
      function loadMeasurements() {
          vis.conn.getStates(sourceDataPoint, (err, state) => {
              if (err || !state[sourceDataPoint] || !state[sourceDataPoint].val) {
                  console.error("Fehler beim Laden der Messwerte:", err || "Keine Daten gefunden");
                  return;
              }
      
              // JSON-Daten parsen
              const data = JSON.parse(state[sourceDataPoint].val);
      
              // Dropdown leeren
              dropdownMenu.innerHTML = "";
      
              // Checkboxen für alle Messwerte generieren
              data.forEach((item) => {
                  const bucket = item.bucket;
                  item.measurements.forEach((measurement) => {
                      const checkboxId = `checkbox-${bucket}-${measurement}`;
                      const checkboxContainer = document.createElement("div");
                      checkboxContainer.style.marginBottom = "5px";
      
                      const checkbox = document.createElement("input");
                      checkbox.type = "checkbox";
                      checkbox.id = checkboxId;
                      checkbox.dataset.bucket = bucket;
                      checkbox.dataset.measurement = measurement;
      
                      const label = document.createElement("label");
                      label.htmlFor = checkboxId;
                      label.textContent = `${bucket}: ${measurement}`;
      
                      checkboxContainer.appendChild(checkbox);
                      checkboxContainer.appendChild(label);
                      dropdownMenu.appendChild(checkboxContainer);
                  });
              });
      
              // Event-Listener für Änderungen an den Checkboxen hinzufügen
              Array.from(dropdownMenu.querySelectorAll("input[type='checkbox']")).forEach((checkbox) => {
                  checkbox.addEventListener("change", saveSelection);
              });
          });
      }
      
      // Funktion: Auswahl speichern
      function saveSelection() {
          const selectedMeasurements = [];
      
          // Alle ausgewählten Checkboxen sammeln
          Array.from(dropdownMenu.querySelectorAll("input[type='checkbox']:checked")).forEach((checkbox) => {
              selectedMeasurements.push({
                  bucket: checkbox.dataset.bucket,
                  measurement: checkbox.dataset.measurement
              });
          });
      
          // Auswahl als JSON-String in den Ziel-Datenpunkt speichern
          vis.setValue(targetDataPoint, JSON.stringify(selectedMeasurements));
      }
      
      // Messwerte beim Start laden
      loadMeasurements();
      
      // Falls sich die verfügbaren Messwerte ändern, neu laden
      vis.conn.subscribe(sourceDataPoint, (id, state) => {
          if (id === sourceDataPoint && state) {
              loadMeasurements();
          }
      });
      
      

      Screenshot Dropdown Menü:

      4631b20a-d5fb-4f0a-8695-f9e670fff3aa-grafik.png

      Wie gesagt im Runtime Modus innerhalb des VIS-Editors funktioniert es einwandfrei, inkl. Speichern der ausgewählten Messwerte.

      Ich nutze VIS-2 2.9.64

      V 1 Reply Last reply Reply Quote 0
      • V
        Vippis @Vippis last edited by

        @vippis

        In der Browser Konsole erscheinen auch keine Fehlermeldungen. Anscheinend wird das Skript gar nicht geladen

        V 1 Reply Last reply Reply Quote 0
        • V
          Vippis @Vippis last edited by Vippis

          @vippis

          Ich löse einmal auf. All Credits to ChatGPT 😁

          Damit sich das Dropdown Menü wie gewünscht auch in der Runtime Umgebung öffent, musste ich den Code in das HTML Widget in den Script Tag aufnehmen.

          Zusätzlich bestand dann das Problem, dass alle Checkbox Labels als "$undefined:$undefined" angezeigt wurden.

          Das Problem liegt daran, dass mein Browser Firefox anscheinend keine Template Strings im Code unterstützt.

          Ich musste die Variablen dann auf einfache String-Verkettung umstellen, dann funktioniert es.

          const checkboxId = "checkbox-" + bucket + "-" + measurement;
          label.textContent = bucket + ": " + measurement;
          

          Hier das vollständige, lauffähige HTML Widget, falls jemand etwas vergleichbares aufbauen möchte:

          <div id="dropdown-container">
              <!-- Button zum Öffnen des Dropdowns -->
              <button id="dropdown-toggle" class="btn_grafana_style">Messwerte auswählen ▼</button>
              
              <!-- Das Dropdown-Menü, das die Checkboxen enthält -->
              <div id="dropdown-menu" style="display: none; max-height: 70vh; overflow-y: auto; position: absolute; background-color: white; border: 1px solid #ccc; padding: 10px; margin-top: 5px;">
                  <!-- Dynamische Inhalte der Checkboxen werden hier eingefügt -->
              </div>
          </div>
          <script>
              // IDs der Datenpunkte
          const sourceDataPoint = "0_userdata.0.Export.Verfügbare_Messwerte"; // JSON mit Messwerten
          const targetDataPoint = "0_userdata.0.Export.Ausgewählte_Messwerte"; // Array für ausgewählte Messwerte
          
          // Dropdown-Elemente
          const dropdownToggle = document.getElementById("dropdown-toggle");
          const dropdownMenu = document.getElementById("dropdown-menu");
          
          // Funktion: Dropdown anzeigen/verstecken
          dropdownToggle.addEventListener("click", (event) => {
              event.stopPropagation(); // Verhindert, dass der Klick das Schließen triggert
              dropdownMenu.style.display = dropdownMenu.style.display === "none" ? "block" : "none";
          });
          
          // Funktion: Schließt das Dropdown, wenn man außerhalb klickt
          document.addEventListener("click", (event) => {
              if (!dropdownMenu.contains(event.target) && event.target !== dropdownToggle) {
                  dropdownMenu.style.display = "none";
              }
          });
          
          // Funktion: Verfügbare Messwerte laden und Checkboxen generieren
          function loadMeasurements() {
              vis.conn.getStates(sourceDataPoint, (err, state) => {
                  if (err || !state[sourceDataPoint] || !state[sourceDataPoint].val) {
                      console.error("Fehler beim Laden der Messwerte:", err || "Keine Daten gefunden");
                      return;
                  }
          
                  // JSON-Daten parsen
                  const data = JSON.parse(state[sourceDataPoint].val);
                  
          
                  // Dropdown leeren
                  dropdownMenu.innerHTML = "";
          
                  // Checkboxen für alle Messwerte generieren
                  data.forEach((item) => {
                      const bucket = item.bucket;
                      item.measurements.forEach((measurement) => {
                          const checkboxId = "checkbox-" + bucket + "-" + measurement;
                          const checkboxContainer = document.createElement("div");
                          checkboxContainer.style.marginBottom = "5px";
          
                          const checkbox = document.createElement("input");
                          checkbox.type = "checkbox";
                          checkbox.id = checkboxId;
                          checkbox.dataset.bucket = bucket;
                          checkbox.dataset.measurement = measurement;
          
                          const label = document.createElement("label");
                          label.htmlFor = checkboxId;
                          label.textContent = bucket + ": " + measurement;
          
                          checkboxContainer.appendChild(checkbox);
                          checkboxContainer.appendChild(label);
                          dropdownMenu.appendChild(checkboxContainer);
                      });
                  });
                  
                  // Event-Listener für Änderungen an den Checkboxen hinzufügen
                  Array.from(dropdownMenu.querySelectorAll("input[type='checkbox']")).forEach((checkbox) => {
                      checkbox.addEventListener("change", saveSelection);
                  });
              });
          }
          
          // Funktion: Auswahl speichern
          function saveSelection() {
              const selectedMeasurements = [];
          
              // Alle ausgewählten Checkboxen sammeln
              Array.from(dropdownMenu.querySelectorAll("input[type='checkbox']:checked")).forEach((checkbox) => {
                  selectedMeasurements.push({
                      bucket: checkbox.dataset.bucket,
                      measurement: checkbox.dataset.measurement
                  });
              });
          
              // Auswahl als JSON-String in den Ziel-Datenpunkt speichern
              vis.setValue(targetDataPoint, JSON.stringify(selectedMeasurements));
          }
          
          // Messwerte beim Start laden
          loadMeasurements();
          
          // Falls sich die verfügbaren Messwerte ändern, neu laden
          vis.conn.subscribe(sourceDataPoint, (id, state) => {
              if (id === sourceDataPoint && state) {
                  loadMeasurements();
              }
          });
          
          </script>
          
          
          OliverIO 1 Reply Last reply Reply Quote 0
          • OliverIO
            OliverIO @Vippis last edited by

            @vippis
            Bei vis2 bin ich mir zwar etwas unsicher, aber bei vis1 wird der Skript Reiter sehr früh geladen und ausgeführt. Zu diesem Zeitpunkt existieren in der Regel die Widgets noch nicht.
            Daher greifen die Anlage der Event
            Listener ins Leere

            Eine weitere Alternative, neben dem, was du jetzt gemacht hast, wäre noch, alle Funktionen in den Skript, Reiter und in den HTML Tag über die Event Attribute, wie beispielsweise onClick

            https://www.w3schools.com/jsref/event_onclick.asp

            dann die Funktion zu definieren.

            1 Reply Last reply Reply Quote 0
            • First post
              Last post

            Support us

            ioBroker
            Community Adapters
            Donate

            959
            Online

            31.7k
            Users

            79.7k
            Topics

            1.3m
            Posts

            2
            4
            216
            Loading More Posts
            • Oldest to Newest
            • Newest to Oldest
            • Most Votes
            Reply
            • Reply as topic
            Log in to reply
            Community
            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
            The ioBroker Community 2014-2023
            logo