Rolf B: Ohne Server-Code geht's gar nicht

Beitrag lesen

Hallo Jochbart,

zuerst ein paar kleinere Antworten:

  1. getElementByClassName funktioniert nicht, weil die Funktion getElementsByClassName heißt. Klassen-Zuordnungen sind nicht eindeutig, deshalb Elements. Du bekommst dann kein Element, sondern eine NodeList mit allen passenden Elementen zurück. Statt getElementsByClassName kannst Du auch querySelector oder querySelectorAll verwenden, das ist etwas allgemeiner. Meine Fiddles haben das immer eingesetzt.

  2. Ich habe Dich belogen - es gibt keine innerHtml Eigenschaft. Sie heißt innerHTML. Deswegen hat das nicht funktioniert, was ich letztens geschrieben habe.

  3. IDs funktionieren in deiner Aufgabenstellung nicht. Es hilft nicht, ein dropdown per id finden zu wollen, nach dem ersten clone hast Du die IDs mehrfach. Deswegen musst Du immer von einem Event-Target (ob nun click, input oder change) hoch zur Section - dafür habe ich Dir eine Funktion gemacht - und von da aus mit getElementsByClassName, querySelector oder querySelectorAll INNERHALB der section zum richtigen Zielelement. Ich habe Dir ein Muster gezeigt, an dem Du Dich orientieren kannst. Oben stehen die Event-Registrierer, diese haben eine KLEINE Inline-Funktion, die sicherstellt dass nur das Event von der richtigen Quelle verarbeitet wird, dann die Section ermittelt und falls nötig noch weitere Daten zum Element. Damit wird dann die Bearbeitungsfunktion aufgerufen.

    Zum Beispiel diese existierende Registrierung hier, für das input-Event der Überschrift:

            form.addEventListener("input", function (evt) {
                if (evt.target.name == "uberschrift")
                   updateHeader(sectionFor(evt.target), evt.target.value);
            });

Hast Du Dir die Doku zu addEventListener durchgelesen? Folgendes ist hier wichtig und sollte von Dir auch für das change-Event auf dem Dropdown beachtet werden!

  • Der Handler wird nicht auf dem Input-Element, sondern auf dem form registriert. Mit Absicht - ein input-Event wird zwar auf dem Input-Element ausgelöst, blubbert dann aber in der Elementhierarchie des Dokuments hoch, bis ganz nach oben zum body-Element (oder sogar bis zum html-Element? Weiß grad nicht). D.h. wenn ich den Eventhandler auf dem form registriere, bekomme ich alle input-Events mit, die irgendwo im form gefeuert werden, ohne mich explizit auf Elemente innerhalb des Forms registrieren zu müssen. Das spart Arbeit beim Registrieren und beim Klonen.
  • Der Handler bekommt als Parameter ein Event-Objekt (-> Doku+Tutorials), und darin gibt's eine Eigenschaft target, in der das Element steht auf dem das Event ausgelöst wurde. Wenn ich das change-Event für alle Dropdowns behandeln will, die für einen Arbeitsplatz die Anzahl der Bilder steuern, dann muss ich diesem select-Element Merkmale geben, die ich abfragen kann. Das kann eine Klasse sein (abfragen mit classList.contains("klassenname")), ein name-Attribut oder ich kann auch den tagName abfragen. Eine ID ist nicht geeignet. IDs müssen auf der Seite eindeutig sein. Das Beispiel oben hat das name-Attribut geprüft. Das kannst Du für das Dropdown auch tun (top10 ist allerdings kein guter Name, weil du ähnliches ja auch noch für die Videos tun willst)
  • Wenn Du außer für die Bilder auch noch ein Dropdown für die Videos haben willst, brauchst Du keine neue Eventhandler-Registrierung. Du hast schon einen Eventhandler, und in dem baust Du eine zweite Prüfung für Event-Quellen ein. Für name="top10" (oder "anzBilder") wird die Liste der Bild-Uploads geändert, und für name="anzVideos" die Liste der Video-Uploads.
  • Wenn die Prüfbedingung für den Auslöser zutrifft, wird die Funktion aufgerufen, die die eigentliche Arbeit tut. Damit diese Funktion sich nicht mit der Rahmenkonstruktion deines HTML beschäftigen muss, habe ich in den Muster-Handlern dafür gesorgt, dass das Auffinden der richtigen Section bereits im Eventhandler erledigt wird. Da steht:
    updateHeader(sectionFor(evt.target), evt.target.value)
    Mir scheint, dass Du noch nicht verstanden hast, was da passiert - du hast diesen Teil nämlich konsequent ignoriert. Hier wird zuerst die sectionFor Funktion aufgerufen und bekommt das Event-Target als Parameter. Die sectionFor-Funktion beginnt bei dem übergebenen DOM Element und sucht sich über die parentNode Kette den Weg nach oben, bis es ein Element mit tagName = 'section' findet. Dein HTML ist so gegliedert, dass jeder Arbeitsplatz in ein <section>...</section> eingeschlossen ist. Das Funktionsergebnis, also das section-Element innerhalb dessen das event ausgelöst wurde, sowie im Beispiel die value-Eigenschaft des Elements auf dem das Event ausgelöst wurde, werden als Parameter an updateHeader übergeben.
  • Dein Handler, der die Upload-Elemente erzeugt, sollte genauso aufgerufen werden. Deine addInputFields Funktion sollte also - so wie updateHeader - zwei Parameter erwarten: Die Section und die Anzahl. Und sie sollte nicht addInputFields heißen, ihr Name sollte darlegen, dass sie die Anzahl der Bilder-Uploads festlegt.
  • Damit das Folgende funktioniert, braucht dein HTML noch eine Anpassung. Das Label mit dem Bild-Upload Element darin muss in einem li in dem vorbereiteten Bilder-ul stehen, sonst hast Du nachher eins zuviel. Und das div mit id="container" ist Kunst, die weg kann.
  • So. In deiner Funktion suchst Du jetzt mit querySelector die Bilderliste. Bis hierher hast Du das in deinem auskommentierten Teil schon alles drinstehen. Die Variable container ist übrigens nutzlos, weil das (a) dein div ist und (b) eine globale Variable ist, die zur ID "container" gehört. Ich habe Dir früher schon geschrieben, dass sich dort eine NodeList befindet, wenn Du 2 Arbeitsplätze hast, kein einzelnes Element.
  • Den Inhalt der Bilderliste kannst Du mit einer Schleife löschen, das geht. Du kannst aber auch frech liste.innerHTML="" setzen 😀
  • Dann hängst Du dem ul die benötigte Zahl von neuen li ein. Im CSS musst Du sicherstellen, dass der list-style von ul.bilder auf none steht, damit Du die kleinen Punkte davor nicht hast. Ggf. musst Du auch noch margin und padding von ul und li anpassen. Da, wo ich name='..' geschrieben habe, musst Du natürlich etwas Zeichenketten-Akrobatik betreiben, damit in den Hochkommas nachher sowas wie bild_7 steht. Tipp: 'bild_'+i funktioniert - JavaScript erkennt, dass da ein String mit einer Zahl verbunden wird und wandelt i in eine Zeichenkette um.
  • Aber, wie ich schon andeutete - es reicht nicht, die Bild-Uploads mit "bild_1" etc zu benamsen. Wenn Du 2 Arbeitsplätze hast, hat Du zwei Uploads mit gleichem Namen und musst das Problem lösen, diese auseinander zu halten. Es gibt hierfür mehrere Strategien, aber welche sinnvoll ist, hängt davon ab was Du am Server treibst.

#Und nun der traurige Teil:

Es betrübt mich, dich betrüben zu müssen: Ohne serverseitigen Code kommst Du meines Wissens nicht weiter. Du brauchst eine Komponente, die die angegebenen Dateien oder Videos entgegennimmt und irgendwo ablädt. Zumindest dann, wenn Du die Dateien über den POST eines HTTP form ablädst. Das kann ein PHP Script sein oder sonst ein programmiertes Artefakt, aber der multipart/form-data Body des POST-Request, den ein HTML-Form mit input type="file" ausspuckt, wird serverseitig nicht ohne dein Zutun verstanden.

Das HTTP Protokoll kennt auch noch andere Verben außer GET und POST - eins davon ist PUT. Wenn Dein Webserver so konfiguriert ist, per PUT Dateien anzunehmen, kannst Du auf diese Weise Dateien hochladen. Aber nicht mit dem Submit eines HTML-Formulars.

PHP ist sicherlich der einfachste Weg, um hier etwas auf die Beine zu bekommen. SelfHTML ist allerdings nicht sehr stark in PHP Tutorials. Wir haben aber ein kleines PHP Portal mit vielen Links.

Speichern der Bilder allein reicht aber nicht. Du brauchst ja auch eine Idee, wie die hochgeladenen Arbeitsplatzinformationen nachher einem Benutzer präsentiert werden können. Und wie Du sie auf deinem Server speichern willst. Eine Datenbank? Eine Verzeichnisstruktur mit einem Ordner pro AP und eine html-Datei, die die Bilder und Videos präsentiert?

Oh f*ck. Ich werde hier noch zum Prof, wenn ich mir den Umfang dieses geistigen Auswurfs betrachte…

Rolf

--
sumpsi - posui - clusi