Rolf B: Nummerierung bei dynamischen Formular

Beitrag lesen

Hallo Jochbart,

das ist jetzt eine Menge, die ich schreiben muss 😀

#Eventregistrierung Bei Fiddle muss man angeben, wann das JavaScript läuft. Dazu klickt man auf das Zahnrad neben dem Wort "JAVASCRIPT" und wählt den LOAD TYPE. Standard ist "onLoad", d.h. jsFiddle wartet für Dich auf das load-Event des Body und führt dein JS dann aus. Das load-Event fliegt aber erst nach DOMContentReady, deshalb wird dein Eventhandler nie ausgeführt.

In meinem Fiddle hatte ich das auf "no wrap - in head" gestellt, weil ich Dir den vollständigen Code zeigen wollte, den Du brauchst, um es im eigenen Script einzusetzen. Wenn ich das bei Dir umstelle, wird das Script ausgeführt bevor die Seite aufgebaut wird und "Neuer Arbeitsplatz" funktioniert wieder.

#Umgang mit einem leeren hdrValue in der updateHeader-Funktion. Bei mir gab's das "Arbeitsplatz" vor dem Zusatztext nicht, deshalb konnte ich mit hdrValue || "Arbeitsplatz" agieren. Lies Dir mal durch, was ich hier geschrieben habe, insbesondere über truthy und falsy, und am Anfang von „Wahrheitstabellen und Kurzschlussreaktionen“ die Info über das zurückgelieferte Ergebnis von ||.

Wenn Du "Arbeitsplatz - " + hdrValue || "Arbeitsplatz" schreibst, wird zunächst die Stringverkettung durchgeführt, weil + Vorrang vor || hat (siehe auch hier). Ist hdrValue == null, wandelt JavaScript den null Wert in den String "null" um und verkettet das. Das Ergebnis ist ein nicht-leerer String, das ist ein truthy Wert und darum ist das das Ergebnis des || Operators. Ich hätte das in meinem Fiddle nicht machen sollen, das ist Expertenwissen zu Javascript. Mach es so:

if (hdrValue != null)
   header.innerText = "Arbeitsplatz - " + hdrValue;
else
   header.innerText = "Arbeitsplatz ";

oder mit ?: Operator so:

header.innerText = hdrValue ? ("Arbeitsplatz - " + hdrValue) : "Arbeitsplatz ";

#Zum Thema „1. Arbeitsplatz - Überschrift“ vs „Arbeitsplatz 1 - Überschrift“ Ich würde das weiterhin mit CSS zählen, weil Du sonst nach jeder Löschung von Hand neu nummerieren musst. Damit das mit CSS funktioniert, nimmst Du den Text "Arbeitsplatz" aus dem Span heraus und lässt den span per Default erstmal leer. Dann musst Du kaum was ändern.

Also im HTML:
<h2>Arbeitsplatz <span></span><button type="button" name="remove">Entfernen</button></h2>

Im CSS:
h2 span:before { content: counter(plaetze); counter-increment: plaetze 1; display:inline; }

Und im JavaScript:
header.innerText = hdrValue ? (" - " + hdrValue) : "";

Jaaa. Und nun zum Horror-Teil.

#Die Bilderliste.

  • kein onchange Attribut am Dropdown! addEventListener("change", ...) mit einer Handler-Funktion. Siehe hier. Es ist dann natürlich etwas umständlicher, das container-Element für die Bilder zu finden - aber da Du mehrere Arbeitsplätze haben kannst, ist ein div mit id="container" ohnehin zum Scheitern verurteilt. Zumindest in Chrome ist es so, dass bei mehr als einem Arbeitsplatz die Variable container nicht mehr auf ein einzelnes div zeigt, sondern ein Array der container enthält. Das JavaScript stürzt dann mit "container.appendChild is not function" ab. Weiter unten mehr dazu.
  • die Eventhandler-Funktion setzt Du, so wie die anderen Handlerfunktionen auch, IN die Handlerfunktion für DOMContentLoaded hinein. Zwei Gründe: (1) Ist es sonst eine globale Funktion, was man vermeiden möchte und (2) hat sie dann Zugriff auf die form-Variable.
  • statt einem div für die Bilderupload-Liste (klingeling!) wäre eine Liste angemessener. Also ein ul als Container und für jedes Bild ein li. ul und li werden so gestyled dass sie keinen margin, kein padding und keinen list-style haben. Die li enthalten dann jeweils ein Upload-Feld. Dem ul gibst Du, um es identifizieren zu können, eine class (weil Du vermutlich die gleich Nummer noch mit Video-Uploads planst). Mein Vorschlag: class="bilder".
  • das von Dir konstruierte HTML passt nicht zu dem vorhandenen Bild-Upload. Du hast das label Element mit darin befindlichem input type="file" aus meinem Fiddle übernommen. Was Du in deinen Container einfügst, ist einfach nur ein input-Element. Deswegen greift das CSS nicht. Das CSS geht von der Struktur <label><span></span><input type="file" ...></label> aus. Da das CSS das label auf display:block setzt, brauchst Du dann auch kein <br> mehr.
  • du hast ein Dropdown "Anzahl der hochzuladenden Bilder". Dein Eventhandler fügt aber soviele input-Felder hinzu, wie man ausgewählt hat. D.h. wenn ich erst 2, dann 3 und dann 9 auswähle, habe ich am Ende 15 Felder. Ist das Dein Wunsch? Möchtest Du nicht vielleicht lieber einen "noch ein Bild" Button haben?

D.h. hinter die Registrierung des input-Events für das form setzt Du die Registrierung und die Filterung auf den richtigen Elementtyp:

form.addEventListener("change", function(evt) {
   if (evt.target.name == "top10")
      updateBilderUpload(sectionFor(evt.target), evt.target.value);
});

und weiter unten, aber nicht zu weit :), dann die Handler-Funktion. Der Rahmen hat bereits die Section und die Anzahl ermittelt. Hier musst Du nun noch die Liste finden und dich entscheiden, wie Du vorgehen willst. Soll es insgesamt so viele Upload-Elemente geben, wie als "anzahl" übergeben wird? Oder sollen so viele Elemente hinzugefügt werden? Davon hängt ab, was die Funktion tun soll, deswegen schreibe ich hier nur einen Rahmen hin.

   function updateBilderUpload(section, anzahl) {
      var liste = section.querySelector("ul.bilder");

      // Beispiel: Ein neues li mit passendem Inhalt erzeugen
      var newItem = document.createElement("li");
      newItem.innerHtml = "<label><span>Bild:</span><input type='file' name='..'></label>"
   }

Bevor wir uns über den Inhalt von updateBilderUpload unterhalten - wie soll's denn sein?

ABER ABER ABER: Du gerätst jetzt in Zuordnungsprobleme. Jedes Bild-Uploadelement hat name="bild". Du hast am Server keine Ahnung mehr, welches Bild zu welchem Arbeitsplatz gehört hat. Vor dem Submit musst Du die name-Elemente aller Bilder patchen, so dass die Arbeitsplatznummer im Bild enthalten ist. Das darfst Du auch erst beim submit-Element des form tun, weil es ja vorher sein kann, dass munter Arbeitsplätze hinzugefügt oder entfernt wurden. D.h. du brauchst einen weiteren Eventhandler:

form.addEventListener("submit", function() {
   // Hier die Namen der input-Elemente systematisch neu nummerieren
});

Dieser Handler sollte dann nicht nur die File-Elemente nummerieren, sondern alle. Um über das "wie" zu reden, wäre erstmal die Frage: Welche Sprache verwendest Du am Server?

Rolf

--
sumpsi - posui - clusi