snooze: Fehlende img-Datei überspringen

Als blutiger Anfänger bin ich über folgendes Problem gestolpert und finde einfach keine Lösung.

Ich lasse über eine For-Schleife (Javascript) nacheinander diverse lokal gespeicherte Fotos anzeigen und wenn ein Bild fehlt, gibt der Browser ein kleines Fehlerbildchen aus, fehlen zum Schluss mehrere, füllt sich die Seite sinnlos mit diesen Symbolen, bis die Schleife durch ist. Kann man das irgendwie programmseitig abstellen, am Besten, indem die Schleife beendet wird, wenn eine im Script als src definierte Datei nicht existiert?

Die HTML soll rein lokal, ohne Webserver, verwendet werden.

Oder kann man rein mit Bordmitteln ein array der Dateien in einem Ordner füllen, das dann vom script abgearbeitet wird (was noch schöner wäre)?

Ich würde mich über eine "Idee für Dummies" sehr freuen.

  1. Hallo snooze,

    Als blutiger Anfänger bin ich über folgendes Problem gestolpert und finde einfach keine Lösung.

    Ich lasse über eine For-Schleife (Javascript)

    while existiert.

    Wenn du bei for bleiben möchtest, gibt es auch break.

    Bis demnächst
    Matthias

    --
    Pantoffeltierchen haben keine Hobbys.
    ¯\_(ツ)_/¯
    1. Okay, danke! Aber wie fange ich den "Fehler" ab, um den break zu setzen?

  2. Hallo,

    Ich lasse über eine For-Schleife (Javascript) nacheinander diverse lokal gespeicherte Fotos anzeigen …

    wie? Zeig mal den Code oder noch besser einen Link zur Testseite.

    Sonst als Tipp: Bilder (img) kennen die Events load und error (onload, onerror).

    var img = document.createElement("img")
    img.onerror = function() { Code für den Fehlerfall }
    img.onload = function() { Code für den Erfogsfall }
    img.src = "...";
    document.body.appendChild(img);
    

    (Ungetestet, so könnte es aussehen.)

    Gruß
    Jürgen

    1. Hallo Jürgen, wie gesagt läuft alles lokal ohne Webserver, deshalb auch kein Link zur Testseite. Bei mir sieht das Script etwa so aus:

      <body> ...

      <div class="container">

        <script>
      
             var txt1 = "<p><a href='Test.html'><img src='A/~Katalog/A";
      
             var txt2 = ".jpg class= 'toppic' /></a></p>";
      
             for(var i=0; i<=100; i++) {
      
                 var txtG =txt1 + i + txt2;
                  
                  document.write(txtG);
      
               }            
          </script>
      

      </div>

      </body>

      Dabei ist die Aufteilung in 2 txt-Variable nur der besseren Lesbarkeit geschuldet. Die Fotos tragen alle den Namen A0.jpg, A1.jpg… Das läuft bestens, wenn ich i<= entsprechend der tatsächlichen Anzahl Bilder definiere. Aber da ich die ja mit Bordmitteln nicht feststellen kann, möchte ich einfach die maximal denkbare Anzahl vorgeben und die Schleife eben abbrechen, wenn die Funktion erstmals kein Bild findet.

      Deinen Tipp werde ich nachher mal ausprobieren, das klingt richtig gut! (Muss aber jetzt erstmal zum Boss...)

      Wie gesagt - ich bin blutiger Laie und versuche gerade, mich etwas einzuarbeiten.

      MfG Helmut

      1. @@snooze

        Deinen Tipp werde ich nachher mal ausprobieren, das klingt richtig gut! (Muss aber jetzt erstmal zum Boss...)

        Waaas? Bruce Springsteen spielt heute und ich weiß von nichts?

        LLAP 🖖

        --
        „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
      2. Hallo,

        der Trick besteht darin, das jedes Bild über das onload-Event das nächste lädt. Wenn es kein nächstes mehr gibt, gibt es auch kein onload-Event mehr. Ich habe da mal etwas gebastelt:

        Script:

        window.addEventListener("DOMContentLoaded", function() {
        	
        	var serienBilder = function(container_id,basisname,platzhalter,zählerstart) {
        		const bildcontainer = document.getElementById(container_id);
        		let count = zählerstart;
        
        		const showImg = function() {
        			let name = basisname.replace(platzhalter,count);
        			let image = document.createElement("img");
        			image.onload = function() {
        				count ++;
        				image.alt = " ";
        				bildcontainer.appendChild(image);
        				showImg();
        			};
        			image.src = name;
        		}
        		
        		showImg();
        	}
        	
        	serienBilder("bilder","An.png","n",1); // A1.png, A2.png, ..., A10.png, ...
        
        },false);
        

        HTML:

        <figure id="bilder"></figure>
        

        Links zur Doku:

        Eventhandler können mit element.addEventListener("Event", … eingerichtet werden oder auch mit element.onEvent = ….

        Sie es dir mal an und versuch zu verstehen, was da passiert.

        Gruß
        Jürgen

        Edit: Ich habe das Script korrigiert, siehe Versionen.

        1. Wow!

          Das sieht ja fantastisch aus - ich versteh nur Bahnhof! Aber ich werde mal versuchen, Deine Idee zu begreifen. Wird wohl eine Weile dauern, aber auf alle Fälle:

          D A N K E !!

          für die schnelle und umfangreiche Antwort.

          Was mir noch Kopfzerbrechen bereitet (neben Deinem Entwurf), ist: wie bekomme ich den Script in den Container (<div class="container">), dessen CSS-Style u.a. "display: flex" vorgibt, und wie weise ich dem img die CSS-styles (class=toppics) mit Größen und Rahmen zu?

          Aber immer eins nach dem anderen...

          Nochmals: Danke!

          1. Hallo,

            das Script gehört in den Seiten-Kopf: https://wiki.selfhtml.org/wiki/JavaScript/Tutorials/Einstieg/Einbindung_in_HTML

            Die Bilder landen dann in dem Element, dessen ID du an die Funktion übergibst, in meinem Beispiel ein figure mit der ID "bilder". Dieses Element kannst du im HTML dann hinlegen, wo du willst und auch mit css ein display: flex geben..

            Gruß
            Jürgen

            1. Uff, ja, ich geb mir Mühe. Da habe ich 'ne Menge zu lesen und zu probieren. Nochmal vielen Dank!

              MfG Helmut

            2. Hallo Jürgen! Vielen Dank für die Ergänzung und Deine Korrektur. Beim Durchlesen des Textes von obigem Link ergab sich bei mir noch eine vielleicht dumme Frage: darf man eigentlich in einer html-Seite auch mehrere .js-Dateien einbinden? Wenn ja, könnte ich ja in dem Bilderverzeichnis eine Info.js ablegen, die als einzige function die Anzahl der Bilder in diesem Ordner (steht ja fest) zurückgibt.

              Helmut

              1. Hallo Helmut,

                mehrere Javascript-Dateien sind möglich. Evtl. solltest du dir für diesesn Fall auch das JSON-Format ansehen.

                Wenn ja, könnte ich ja in dem Bilderverzeichnis eine Info.js ablegen, die als einzige function die Anzahl der Bilder in diesem Ordner (steht ja fest) zurückgibt.

                dann würde ich aber direkt eine Datei mit den Dateinamen anlegen, dann bist du nicht auf Bild1, Bild2, ... beschränkt.

                Reicht die mein oder Gunnars Beispiel nicht?

                Gruß
                Jürgen

                1. Danke für die Auskunft. Ich habe nur gefragt, weil in dem von Dir verlinkten Kapitel in einem Beispiel zwei Einbindungen von script1.js und script2.js erfolgen. In Verbindung mit der weiter unten von Rolf B erwähnten Info-Datei kam mir dann dieser Gedanke.

                  Natürlich sind die von Gunnar und Dir ausgearbeiteten Lösungen weit eleganter und hochwertiger als der Kram, den ich zusammengestümpert habe, entschuldige, wenn das falsch rüber kam.

                  Wie gesagt - ich präferiere (schon aus besserem Verständnis heraus) Deinen Ansatz und werde versuchen, ihn in mein Konstrukt einzubauen. Mal sehen, ob ich damit klar komme.

                  Schönen Gruß Helmut

        2. @@JürgenB

          der Trick besteht darin, das jedes Bild über das onload-Event das nächste lädt. Wenn es kein nächstes mehr gibt, gibt es auch kein onload-Event mehr. Ich habe da mal etwas gebastelt

          Ich auch – mit dem Fetch-API, was ich hier für den besseren Trick halte:

          Codepen. Und ja, das funktioniert auch lokal übers Dateisystem.

          Dabei habe ich das erste Beispiel von der fetch()-Seite übernommen und geringfügug modifiziert, sodass ein neues li-Element mit img darin generiert wird:

          			listElement.insertAdjacentHTML('beforeend', `
          				<li>
          					<img src="${}" alt=""/>
          				</li>
          			`);
          

          (insertAdjacentHTML() FTW, das macht die Sache einfacher als jedes Element einzeln erzeugen, jedes Attribut einzeln setzen und dann alles ins DOM zu hängen.)

          Und das Ganze in eine Funktion gepackt, die sich selbst wieder aufruft – fast wie bei dir; nur dass meine Funktion den Index als Parameter hat:

          fetchTarget(1);
          
          function fetchTarget(index)
          {
          	// …
          	fetchTarget(index + 1);
          }
          

          Du steuerst das über eine globale Zählvariable – find ich unschön:

          let count = 1;
          showImg();
          
          function showImg()
          {
          	// …
          	count++;
          	showImg();
          }
          

          LLAP 🖖

          --
          „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
          1. Hallo Gunnar,

            ob deine modernere Version besser für einen Anfänger ist, als meine, weiß ich nicht. Aber zwei Fragen:

            Wie sieht es mit der Browserunterstützung aus (fetch, Strings in ``)?

            Funtioniert fetch wirklich in allen Browsern vom lokalen Filesystem? XMLHttpRequest funktioniert lokal nur noch im Firefox.

            Du steuerst das über eine globale Zählvariable – find ich unschön:

            so richtig global ist mein Zähler ja nicht, ich habe ja das ganze in einer Funktion verpackt.

            Gruß
            Jürgen

            PS In meiner Version steckte noch ein Fehler: das appendChild muss in den onload-Handler.

            1. @@JürgenB

              Wie sieht es mit der Browserunterstützung aus (fetch, Strings in ``)?

              Da die Anwendung hier wohl für einen sehr eingeschränkten Nutzerkreis ist, sollte das kaum eine Rolle spielen.

              Funtioniert fetch wirklich in allen Browsern vom lokalen Filesystem? XMLHttpRequest funktioniert lokal nur noch im Firefox.

              Das schon eher. Meh, du hast recht: geht nicht in Safari und Chrome. Und wer weiß, ob’s in zukünftigen Versionen von Firefox noch gehen wird. Dann muss man für diesen Anwendungsfall wohl wirklich übers load-Event gehen.

              Du steuerst das über eine globale Zählvariable – find ich unschön:

              so richtig global ist mein Zähler ja nicht, ich habe ja das ganze in einer Funktion verpackt.

              Ob nun superglobal oder nicht so richtig global – jedenfalls außerhalb der Funktion showImg, und das muss ja nicht sein.

              LLAP 🖖

              --
              „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
              1. Moin Gunnar, moin Jürgen!

                Entschuldigt, dass ich jetzt erst antworte - ich habe noch so einen kleinen Nebenjob zu erledigen. Wir verwenden Chrome und Firefox - damit kommt dein Vorschlag, Gunnar, wohl nicht so gut infrage.

                Außerdem muss ich zu meiner Schande gestehen, dass ich Jürgens Modell ziemlich überzeugend finde. Ich habe gestern Abend noch eine Weile über dem Script gebrütet und hoffe, jetzt den Ablauf verstanden zu haben. Ich werde es, sobald meine Zeit es zulässt, in meiner Seite ausprobieren.

                Unten habe ich in meiner Antwort an Rolf B noch ein wenig zum Hintergrund meiner Anfrage geplaudert - falls es jemanden interessiert.

                Euch allen ganz herzlichen Dank für die sehr nette, freundliche und hilfsbereite Reaktion auf meine doch ziemlich unbedarfte Anfrage und schöne Grüße aus dem sonnigen Eckernförde!

                Helmut

                1. @@snooze

                  Außerdem muss ich zu meiner Schande gestehen, dass ich Jürgens Modell ziemlich überzeugend finde.

                  So dolle unterscheiden sich unsere Ansätze gar nicht:

                  Jürgens Ansatz mein Ansatz
                  1. generiere ein ImageElement 1. fordere das Bild vom Server an
                  2. fordere das Bild vom Server an 2. Abbruch, wenn das Bild nicht geladen wurde
                  3. Abbruch, wenn das Bild nicht geladen wurde 3. generiere ein ImageElement
                  4. hänge das ImageElement ins DOM 4. hänge das ImageElement ins DOM
                  5. rufe die Funktion fürs nächste Bild auf 5. rufe die Funktion fürs nächste Bild auf

                  Die Reihenfolge ist etwas anders. Der Rest sind Feinheiten, z.B. dass ich die Bilder jeweils noch in ein Listitem-Element gepackt habe.

                  Ich habe mal Jürgens Ansatz in einem Fork meines Pens nachgebaut.

                  LLAP 🖖

                  --
                  „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                  1. @@Gunnar Bittersmann

                    Ich habe mal Jürgens Ansatz in einem Fork meines Pens nachgebaut.

                    Funfact: Und wie ich da so am Bauen war, zeigte das Ding auf einmal nicht nur 17, sondern 18 Bilder an! Der Algorithmus funktioniert!

                    Na bloß gut, dass ich meinen Codepen hatte, sonst hätte ich Target #18 glatt verpasst!

                    Unnötig zu erwähnen, dass meine momentare Lösung für #18 noch meilenweit (60 Zeichen) hinter der Top-Lösung zurückhängt.

                    LLAP 🖖

                    --
                    „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                  2. Hallo Gunnar,

                    moi? Mais non!

                    Rolf, nicht Jürgen, B

                    --
                    sumpsi - posui - clusi
                    1. @@Rolf B

                      Wie konnte denn das passieren‽

                      Mais non!

                      Kein Mais? Allergie?

                      LLAP 🖖

                      --
                      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
  3. @@snooze

    Ich lasse über eine For-Schleife (Javascript) nacheinander diverse lokal gespeicherte Fotos anzeigen

    Ich nehme an, dann liegen keine zugehörigen Alternativtexte vor. Was dich nicht davon abhalten sollte, das alt-Attribut zu setzen …

    und wenn ein Bild fehlt, gibt der Browser ein kleines Fehlerbildchen aus […] Kann man das irgendwie programmseitig abstellen

    Ja. Das alt-Attribut hier nicht auf den leeren Wert, sondern ein Leerzeichen alt=" " setzen; siehe Codepen.

    am Besten, indem die Schleife beendet wird, wenn eine im Script als src definierte Datei nicht existiert?

    Warum soll ein Script-Abbruch besser sein als alle vorhandenen Bilder anzuzeigen?

    LLAP 🖖

    --
    „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
    1. Hallo Gunnar!

      Stimmt, Alternativtexte hatte ich bisher nicht. Hab ich eingefügt (Leerzeichen) - das zerbrochene Bildchen bleibt (Chrome und Firefox, beides aktuell). Wenn ich Text eingebe erscheint das Bildchen plus Text.

      Ich kann sicherstellen, dass alle Bilder von A1 bis Axx durchgehend vorhanden sind, weiß aber je Ordner nicht, wieviele Bilder in dem jeweiligen Ordner sind (sehr unterschiedlich, Minimum ist aktuell 4, Maximum ist 297, ca. 200 Ordner). Ich habe endlos gesucht, aber es gibt anscheinend mit Bordmitteln keine Möglichkeit, die Anzahl der Dateien im Ordner zu ermitteln (was mir unverständlich ist, denn ich kann ja auch auf diese Dateien zugreifen und sie anzeigen). Deshalb wäre es schön die Schleife einfach abbrechen zu können, wenn kein Bild mehr da ist.

      1. Hallo snooze,

        dass du Dateien abrufen kannst, aber kein Verzeichnis auflisten, ist eine Sicherheitsmaßnahme der Browser gegen böswilliges JavaScript. Die Event gesteuerte Methode mit onload, um bei Erfolg mit Bild x das Bild (x+1) anzufordern, ist deshalb die einzige Methode, die ohne einen Webserver oder andere Tools verlässlich ist.

        Was schön wäre, aber auch nicht funktioniert, ist eine Info Datei, die du im Ordner ablegst und per Ajax holst. Auch da streiken Browser.

        Du könntest aber - leicht über den Tellerrand hinaus gedacht - mit einem Tool, das nicht im Browser läuft (geschrieben in PHP oder JavaScript unter node.js oder Java oder C# oder Powershell oder Bash oder weißdergeierwas), eine HTML Seite generieren, die alle Bilder in einem Ordner anzeigt. Aufruf von Ordner X bedeutet dann Anzeige von X.html. Kommt ein Bild hinzu, musst du das HTML neu generieren. D.h. du darfst für diese Dateien keine langen Cache-Zeiten zulassen.

        Rolf

        --
        sumpsi - posui - clusi
        1. Hi, Rolf! Jo - ich habe den Katalog, um den es sich hier dreht, vor Jahren bereits in Visual Basic (damals noch 4) realisiert, das war echt einfach, schon weil man damals Steuerelemente etc. direkt als Array definieren konnte (was in späteren Versionen unbegreiflicherweise abgeschafft wurde). Dann portiert auf VB 20xx, zuletzt auf VB 2017 (auch mit dynamischen Arrays, allerdings deutlich komplizierter als unter VB4). Läuft heute noch direkt von DVD - aber nur unter Windows. Mein Versuch, dasselbe als Web-Anwendung zu bauen - und hier bin ich wirklich totaler Anfänger! - sollte diese Einschränkung aufheben: man braucht nur noch nen Browser, egal welches Betriebssystem etc.

          Zu der angesprochenen Sicherheit: Kann ich für den Client nachvollziehen, aber meine Dateien liegen alle im selben Verzeichnis wie die index.html (oder einem Unterverzeichnis davon). Für eine Website also alle auf dem Webserver, nicht auf dem Client. Und nun muss ich nur, um die Anzahl von Dateien im Sourceverzeichnis zu ermitteln, derartige Handstände machen. Das macht mich traurig.

          1. Hallo snooze,

            den Saboteuren da draußen ist es egal ob du traurig bist. Aber man muss als Browserhersteller trotzdem darauf achten, ihnen das Leben schwer zu machen.

            Der angestammte Lebensraum von HTML Selten ist das Web. D.h. Server und Clients. file:/// basierende Anwendungen, vor allem von externen Datenträgern, sind eine Nischennutzung. Mit den Folgen musst du leider leben.

            Aber verstehe ich das richtig? Du erstellst eine DVD, von der der Katalog per Index.html angerufen wird?

            In dem Fall solltest du auf dynamische Ermittlung von Verzeichnisinhalten verzichten. Das wird ewig dauern. Das Authoring einer DVD darf gerne etwas Vorbereitung in Anspruch nehmen, und das wichtigste Ziel muss sein, Bewegungen des Lesekopfes zu vermeiden. Heißt: möglichst wenige und große Dateien, um die Lesevorgänge zu streamen. Generiere die HTML Seiten, und zwar so, dass (außer den Bildern) alles enthalten ist. Den Generator kannst du in dir vertrautem VB schreiben.

            Rolf

            --
            sumpsi - posui - clusi
            1. Oh, das hatte ich falsch verstanden, sorry! Okay, das klingt jetzt doch sehr gut, und mit diesem Tool wäre auch die Pflege zukünftiger Ausgaben deutlich einfacher. Da muss ich wirklich mal in mich gehen. Allerdings möchte ich als erstes, bevor ich mich an VB setze, das schöne Script von Jürgen ausprobieren.

              Danke für den Tipp!

              Helmut

      2. @@snooze

        Stimmt, Alternativtexte hatte ich bisher nicht.

        Das alt-Attribut ist (meist) Pflicht, auch wenn kein Alternativtext vorhanden ist. Screenreader lesen sonst den Dateinamen vor. Oder wäre das in diesem Fall besser als gar nichts?

        Hab ich eingefügt (Leerzeichen) - das zerbrochene Bildchen bleibt (Chrome und Firefox, beides aktuell).

        Ups, ich hatte nur im Firefox (macOS) getestet; da ist das zerbrochene Bildchen weg. Sollte sich der Firefox unter Windows anders verhalten?

        Wenn ich Text eingebe erscheint das Bildchen plus Text.

        In Chrome ist das so. Safari zeigt nur das Bildchen, WFT‽ Das halte ich für einen Bug, kein Feature.

        LLAP 🖖

        --
        „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
        1. Was auch immer in der Nacht passiert ist - sowohl chrome als auch firefox zeigen bei leerem alt-attribut jetzt kein Bildchen mehr an. Seufz! Ich muss wohl beim Test was falsch gemacht haben. Ist aber auch egal, denn stattdessen sehe ich nun den per CSS erzeugten Rahmen: bei Firefox in voller Pracht und Größe (mit einem winzigen Fehlerbildchen drin), in Chrome nur als kleines Quadrat. Es bleibt schwierig.