Ja, ich denke ich verstehe es. Du hast da ja ein variables Formular wo die Felder nach Bedarf ein- und ausgeblendet werden. Wahrscheinlich kommen wir dann nicht daran vorbei, es Feld für Feld zu prüfen, wie Du es anfangs hattest. Ich sehe mir das mal an.
Beiträge von Sempervivum
-
-
-
Hier jetzt das Javascript für die Überprüfung ob alles OK ist und das Abschicken mit fetch. Ungetestet, wenn es nicht gleich läuft, versuche selbst, den Fehler zu finden.
Code
Alles anzeigen} else if (verein === "freitext") { var freitextfeld = document.getElementById("freitextfeld").value; json = [ { "text": [74, 5, "MUSIKKAPELLE", "fonts/bahnschrift20", 1] }, { "text": [10, 63, freitextfeld, "t0_14b_tf", 1] }, { "text": [48, 105, "Ort", "fonts/bahnschrift20", 1] } ]; } // var image = document.getElementById("image"); // image.value = JSON.stringify(json); // document.getElementById("jsonupload").submit(); // Gibt es keine Elemente mehr, die "invalid" sind? const invalidElems = document.querySelectorAll('form :invalid'); if (invalidElems.length == 0) { // Alle Elemente OK, wir können das JSON hochladen params = new FormData(); params.append('json', json); fetch('/jsonupload', { method: 'post', body: params }).then(response => text()).then(txt => { // hier steht jetzt die Antwort vom Skript // als Text bereit. Wir können sie evtl. auswerten // und einen Hinweis anzeigen, dass die Verarbeitung // erfolgreich war oder auch nicht. }); } else { // Es gibt Elemente, wo die Eingabe nicht OK ist. // Einen Hinweis für den Benutzer anzeigen: alert('Eingaben noch nicht vollständig korrekt'); } } -
Danke, das hilft wirklich für ein besseres Verständnis und es wird sofort klar, dass Name und Nummer getrennt sein müssen. Ich antworte gleich wegen der anderen Dinge.
-
PS: Man kann auch auf die browsereigene Validierung aufbauen, das würde dann so aussehen:
Code
Alles anzeigen// Eventlistener für Eingabe registrieren window.addEventListener('input', event => { // Wurde in ein Auswahlfeld für ein Lied eingeben? if (event.target.matches('[list="datalist-lieder"]')) { const val = event.target.value; // Ist der Wert des Eingabefeldes in den // Optionen enthalten? if (document.querySelector(`option[value="${val}"`)) { console.log('valid'); // Element auf "valid" setzen event.target.setCustomValidity("");; } else { console.log('invalid'); // Element auf "invalid" setzen event.target.setCustomValidity("Ungültige Eingabe");; } } }); document.querySelector('#send-it').addEventListener('click', event => { // Dadurch dass wir jetzt die browsereigene Validierung benutzen // brauchen wir nur noch zu prüfen ob irgend ein Element ungültig is if (document.querySelector(':invalid')) { alert('Ungültige Eingabe'); // Default-Aktion, Abschicken des Formulars, unterdrücken event.preventDefault(); } });Im CSS müssen wir uns dann auf die Pseudoklasse beziehen:
-
Jetzt verstehe ich, was Du mit Wertevorrat meintest. Das ist nicht ganz so einfach wie es zunächst scheint weil man ja nicht einfach die Eingaben des Benutzers unterbinden kann. Man müsste abwarten bis er das JSON abschickt und es dann blockieren mit einem geeigneten Hinweis.
Versuche dies, zunächst einen Button für das Abschicken des JSON:
Und dann dies Javascript:
Code
Alles anzeigen// Eventlistener für Eingabe registrieren window.addEventListener('input', event => { // Wurde in ein Auswahlfeld für ein Lied eingeben? if (event.target.matches('[list="datalist-lieder"]')) { const val = event.target.value; // Ist der Wert des Eingabefeldes in den // Optionen enthalten? if (document.querySelector(`option[value="${val}"`)) { console.log('valid'); // Klasse "invalid" hinzu fügen event.target.classList.remove('invalid'); } else { console.log('invalid'); // Klasse "invalid" löschen event.target.classList.add('invalid'); } } }); document.querySelector('#send-it').addEventListener('click', event => { if (document.querySelector('#input-liedname-1').classList.contains('invalid') || document.querySelector('#input-liedname-2').classList.contains('invalid')) { alert('Ungültige Eingabe'); // Default-Aktion, Abschicken des Formulars, unterdrücken event.preventDefault(); } });Es fügt eine Klasse "invalid" hinzu wenn die Eingabe ungültig ist. Damit können wir die Darstellung des Eingabefeldes mit CSS ändern, z. B. so:
Wird bei ungültiger Eingabe der Button gedrückt, bekommt der Benutzer einen Hinweis.
-
Was dieses betrifft:
ZitatWo ich auch eine Lösung finden wollte, aber noch nichts gefunden habe ist folgendes.
Wenn auf Übertragen geklickt wird, kommt eine Bestätigungsseite. Besser wäre natürlich man würde auf der Seite bleiben und der Button würde z.B. auf Reset wechseln und die Felder wieder zurücksetzen, oder die Seite neu laden.
Wo liegt denn diese HTML-Seite? Du kannst sie ja selbst ändern. Wird sie dann auf den ESP hoch geladen oder bleibt sie lokal und Du öffnest sie irgend wie durch Doppelklick o. ä.?
-
Guten Morgen!
So wie Du zuvor zwei Eingabefelder gebraucht hast, wirst Du jetzt zwei Auswahllisten brauchen. Ich dachte erst, wir müssten auch die Liste verdoppeln aber das ist gar nicht nötig, die beiden können die selbe datalist verwenden:
Code<label>Lied 1: <input id="input-liedname-1" list="datalist-lieder" type="text"></label> <label>Lied 2: <input id="input-liedname-2" list="datalist-lieder" type="text"></label> <datalist id="datalist-lieder"> </datalist>Die Generierung mit der for-of-Schleife bleibt dann wie sie ist.
Und die Werte kannst Du dann so heraus holen:
Zunächst eine Funktion definieren:
Codefunction liedHolen(sel) { inputLied = document.querySelector(sel); const splitted = inputLied ? inputLied.value.split(': ') : ['', '']; return { nr: splitted[0], name: splitted[1] }; }Und dann damit die Werte holen:
Code
Alles anzeigenif (verein === "liednummer1") { json = [ {"text":[148,5,"MUSIKKAPELLE","fonts/bahnschrift20",1,1]}, {"text":[148,26,nr1,"fonts/calibrib80",1,1]}, {"text":[148,97,name1,"t0_14b_tf",1,1]}, {"text":[148,106,"ORT","fonts/bahnschrift20",1,1]} ]; } else if (verein === "liednummer2") { var lied1 = liedHolen('#input-liedname-1'); var lied2 = liedHolen('#input-liedname-2'); // Jetzt stehen Nummer und Name in den Variablen bereit. // nummer1 = lied1.nr usw. // Wir können aber problemlos auf die Zwischenvariablen // nummer und name verzichten: json = [ {"text": [148,5,"MUSIKKAPELLE","fonts/bahnschrift20",1,1]}, {"text": [7,26,lied1.nr,"fonts/calibrib80",1]}, {"text":[10,97,lied1.name,"t0_14b_tf",1]}, {"triangle": [134,51,134,81,164,66,1]}, {"text": [165,26,lied2.nr,"fonts/calibrib80",1]}, {"text":[160,97,lied2.name,"t0_14b_tf",1]}, {"text": [148,106,"ORT", "fonts/bahnschrift20",1,1]} ]; lied1 = liedHolen('#input-liedname-1'); lied2 = liedHolen('#input-liedname-2'); -
Hm, ich habe gerade deinen Code in meine Testdatei übernommen und da kommen die Vorschläge. Sieh doch mal in der Console nach ob da Fehlermeldungen kommen.
Nummer und Name kann man auf diese Weise aufteilen:
Code
Alles anzeigen<script> const liednamen = { '1': 'Sternenbanner', '2': 'Weil ich dich gerne mag', '3': 'Posaunenparade', '10': 'Lieblingstück', '11': 'Trompetenserenade', '12': 'Hinter dem Wald', '123': 'Walzerliebe', '123': 'Wiener Marsch', '312': 'Dixie Land Parade', '402': 'Schritt für Schritt' }, datalistLieder = document.querySelector('#datalist-lieder'), inputLiednamen = document.querySelector('#input-liedname'); for (const [key, value] of Object.entries(liednamen)) { const html = `<option value="${key}: ${value}"></option>`; datalistLieder.insertAdjacentHTML('beforeend', html); } </script> </body>Und dann kannst Du Nummer und Name so ermitteln:
-
Auch das ist recht einfach weil es heute das datalist-Element gibt. Füge dies statt des Eingabefeldes für die Nummer ins HTML ein:
Code<label>Liednamen: <input id="input-liedname" list="datalist-lieder" type="text"></label> <datalist id="datalist-lieder"> </datalist>Und dies am Ende des body, vor dem schließenden </body>:
Code
Alles anzeigen<script> const liednamen = { '1': 'Sternenbanner', '2': 'Weil ich dich gerne mag', '3': 'Posaunenparade', '10': 'Lieblingstück', '11': 'Trompetenserenade', '12': 'Hinter dem Wald', '123': 'Walzerliebe', '123': 'Wiener Marsch', '312': 'Dixie Land Parade', '402': 'Schritt für Schritt' }, datalistLieder = document.querySelector('#datalist-lieder'), inputLiedname = document.querySelector('#input-liedname'); for (const [key, value] of Object.entries(liednamen)) { const html = `<option value="${key}: ${value}"></option>`; datalistLieder.insertAdjacentHTML('beforeend', html); } </script> </body>Edit, ich vergaß, auf Nummer und Liedname kannst Du dann so zugreifen:
Codevar json; var verein = document.querySelector('input[name="verein"]:checked').value; if (verein === "liednummer1") { var liedname = inputLiedname.value; json = [ {"text":[74,5,"MUSIKKAPELLE","fonts/bahnschrift20",1]}, //{"text":[83,36,nummer1,"fonts/calibrib80",1]}, {"text":[95,36,liedname,"fonts/calibrib80",1]}, {"text":[48,105,"ORT","fonts/bahnschrift20",1]}Über die Anordnung muss man vielleicht noch nachdenken. Müssen da Nummer und Name getrennt sein? Wäre auch kein Problem.
-
Immer gern, freut mich, dass Du zufrieden bist.
Hat der Dirigent denn alle Nummern im Kopf? Es würde sich nämlich anbieten, direkt die Liste der Namen zu zeigen und durch Eingabe von zwei oder drei Buchstaben werden dann die passenden Namen angezeigt.
-
Das Ganze gestaltet sich viel einfacher als ich zunächst erwartet hatte. Als ersten Schritt schlage ich vor, dass wir das mit festem Javascript machen:
Ich habe die wenigen Einträge in der CSV-Datei von Hand umeditiert. Füge dies in das Javascript oben ein:
Code
Alles anzeigenconst liednamen = { '1': 'Sternenbanner', '2': 'Weil ich dich gerne mag', '3': 'Posaunenparade', '10': 'Lieblingstück', '11': 'Trompetenserenade', '12': 'Hinter dem Wald', '123': 'Walzerliebe', '123': 'Wiener Marsch', '312': 'Dixie Land Parade', '402': 'Schritt für Schritt' };Dann kannst Du in dem Code aus #14 den Text ganz einfach aus der Nummer ermitteln:
Codevar json; var verein = document.querySelector('input[name="verein"]:checked').value; if (verein === "liednummer1") { var nummer1 = document.getElementById("nummer1").value; var liedname = liednamen[nummer1]; // <-- hier json = [ {"text":[74,5,"MUSIKKAPELLE","fonts/bahnschrift20",1]}, {"text":[83,36,nummer1,"fonts/calibrib80",1]}, {"text":[95,36,liedname,"fonts/calibrib80",1]}, {"text":[48,105,"ORT","fonts/bahnschrift20",1]}Ich dachte zunächst daran, eine Funktion holeLiedName zu machen aber wie Du siehst ist das so einfach, dass es nicht lohnt.
Wenn das funktioniert, gehen wir daran, die CSV-Datei zu laden und auszuwerten.
-
Danke, ich sehe mir das dann genauer an. Aber im Laufe des Tages noch nicht, vielleicht heute Abend.
-
Excel wäre günstiger als Word weil man das als CSV exportieren kann und dann problemlos durch ein Skript auswerten. Vielleicht kann man da etwas machen, dass Du es irgend wie nach Excel herüber bringst?
-
OK, ich denke, jetzt verstehe ich es: Das JSON gibt die Struktur eines Konzertes wieder und dort sollen dynamisch die Texte aus dem Vorrat von 250 eingetragen werden.
Gibt es die 250 Stücke denn schon in irgend einer Form als Datei, z. B. Excel, so dass man sie durch ein Skript einlesen könnte? 250 sind ja schon ein ganze Menge und es wäre viel Arbeit, sie von Hand einzutragen.
-
Zitat
Also die Seite kann man ändern. Die habe ich erstellt. Die kann ich also jederzeit austauschen gegen das was ich will.
Das ist ja schon mal eine gute Nachricht und vereinfacht die Sache stark.
Zitates handelt sich hier um ca. 250 Datensätze bestehend aus "NR" und "NAME"
Das verstehe ich jetzt wieder nicht: Im JSON in der HTML-Datei nur wenige Einträge und jetzt um 250?
-
PS, Ich vergaß ganz: Man könnte auch daran denken, eine unabhängige Seite lokal abzulegen. Dann würde man aber Probleme mit der SOP bekommen, wenn man diese einfach öffnet und mit dem file-Protokoll lädt.
-
Guten Abend,
das ist ja wirklich eine überschaubare Anzahl an Elementen oder hast Du das JSON gekürzt?
Ich dachte zunächst daran, einfach das JSON im Quelltext um die Texte zu erweitern aber das geht nicht, wenn ich das richtig verstehe, weil die HTML-Seite vom ESP kommt und Du sie dort nicht ändern kannst. Sehe ich das richtig? Auch das Einfügen von zusätzlichem Javascript ist dann nicht möglich.
Mir fällt da die Lösung ein, die Änderungen durch ein Userscript mit Tampermonkey zu machen, dafür müsste diese Erweiterung im Browser installiert werden. Wäre das eine Möglichkeit?
Ich schließe jetzt erst Mal den Tag ab, gute Nacht. Vielleicht kann sich heute Abend noch jemand anders dieser Sache annehmen.
-
Guten Abend Crazyman,
Du brauchst auch nicht auf "background-size: cover;" zu verzichten, denn es gibt auch "object-fit: cover;" für Bilder, die keine Hintergrundbilder sind, siehe hier:
img-Bilder mit CSS einpassen - object-fit: und object-position:direkt in HTML integrierte Bilder werden mit CSS in Bereiche eingepasst über object-fit: contain, object-fit:cover, object-fit:fill, object-fit:none,…www.html-seminar.deWichtig dabei ist, dass man dem Bild die Größe geben muss, in die der Browser es einpassen soll, in diesem Fall 100% für Breite und Höhe, damit das Bild seinen Container ausfüllt. Nachdem ich das getan hatte, hat es immer noch nicht richtig funktioniert und ich musste bei Stackoverflow nachlesen:
SVG image not aligning to equivalent of 'object-fit' in 100vh viewportI'm trying to get an SVG image to be the equivalent of object-fit inside an 100vh full screen container. From what I can gather I need to use the…stackoverflow.compreserveAspectRatio="xMidYMid slice" war die Lösung.
Damit funktioniert es dann, die Bilder stehen wie fest genagelt übereinander, egal, wie man die Größe des Browserfensters zieht.
Etwas unschön ist, dass ich das SVG durch Transformation an die richtige Position und die richtige Größe bringen musste. Besser wäre es, wenn Du die Formen so ändern könntest, dass das Bild von Anfang an die richtige Größe hat und die Formen darin die richtige Position.
Hier das vollständige HTML und CSS, ich war so frei und habe einige überflüssige Container entfernt:
HTML
Alles anzeigen<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Image SVG Cover</title> <style> html, body { height: 100%; } body { margin: 0; } #my-svg { width: 100%; height: 100%; object-fit: cover; vertical-align: top; /* Ein wenig unschön: Wir bringen durch Transformation das Bild an die richtige Stelle und in die richtige Größe */ transform: scale(0.5) translate(0, -45px); transform-origin: center center; vertical-align: top; } .mainnav { height: 100%; margin: 0; padding: 0; background-image: url(https://fakeimg.pl/1920x1440/?text=World&font=lobster); background-position: center; background-repeat: no-repeat; background-size: cover; } .clickable-area { background-color: rgba(255, 0, 0, 0.5); /* Hier kannst du die gewünschte Hintergrundfarbe einstellen (hier: halbtransparentes Rot) */ cursor: crosshair; } </style> </head> <body> <main class="mainnav"> <svg id="my-svg" viewBox="0 0 1920 1440" preserveAspectRatio="xMidYMid slice"> <path fill="#ff0000" stroke="#000000" d="M780,513L860,479L832,336L573,397L683,453L751,460Z" fill-opacity=".6" stroke-width="1" stroke-opacity=".8" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0); fill-opacity: 0.6; stroke-opacity: 0.8;"> </path> <polyline fill="none" stroke="#88CE02" stroke-width="4" stroke-miterlimit="10" points="1038,871,1147,808,1238,834,1335,900,1187,985,1137,925" /> </svg> </main> </body> </html> -
Interessante Sache. Jetzt ist mir aber immer noch nicht klar, was der ESP damit macht. Zeigt er die Noten an?