javascriptsortingfilereaderalphabeticalalphabetical-sort

Problem trying to sort images alphabetically by file name that have been loaded into a div via file reader


I am trying to load images into an html document using the file reader API, and then sorting them alphabetically. The code I have written loads the images into the div just fine, however it doesn't sort the images in alphabetical order, instead it loads them into the document seemingly at random. I have tried using the following code to sort the images but to no avail: files.sort((a, b) => a.name.localeCompare(b.name)); Would appreciate any help that you can provide.

document.getElementById('loadImageButton').addEventListener('click', () => {
    document.getElementById('imageInput').click(); 
});

document.getElementById('imageInput').addEventListener('change', (event) => {
    let files = Array.from(event.target.files);
    const imageContainer = document.getElementById('imageContainer');
    imageContainer.innerHTML = '';
    
    console.log('Before Sort: ', files);
    
  // Sort files alphabetically by name
    files.sort((a, b) => a.name.localeCompare(b.name));
    
    
    console.log('After Sort: ', files);
    

    files.forEach(file => {
        if (file.type.startsWith('image/')) {
            const reader = new FileReader();

            reader.onload = (e) => {
                const img = document.createElement('img');
                img.src = e.target.result;
                img.alt = file.name; // Use file name as alt text
                imageContainer.appendChild(img);
            console.log('Image as appended: ', img);
            };

            reader.readAsDataURL(file);
        }
    });
});
#imageContainer {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    border: 1px solid #ccc;
    padding: 10px;
    min-height: 100px;
  }
  #imageContainer img {
    width: 150px;
    height: auto;
  }
<input type="file" id="imageInput" accept="image/*" multiple style="display: none;">
<button id="loadImageButton">Import Images</button>
<div id="imageContainer"></div>

Wrote the above code expecting the images to be loaded into the imageContainer div in alphabetical order, instead they seem to be loaded in a random order.


Solution

  • From your comment you don't want to get held up should an image not load or take a long time to load,

    So one thing you can do is alter the sequence of loading and creating/appending the img element.

    As your array is sorted into the correct order, create and append an img element in that order. Just don't put in the actual src attribute yet, leave that until you are sure the image has loaded.

    That way, the img elements are in the correct order but you aren't held up should an image fail to load.

    <style>
      #imageContainer {
        display: flex;
        flex-wrap: wrap;
        gap: 10px;
        border: 1px solid #ccc;
        padding: 10px;
        min-height: 100px;
      }
    
      #imageContainer img {
        width: 150px;
        height: auto;
      }
    </style>
    <input type="file" id="imageInput" accept="image/*" multiple style="display: none;">
    <button id="loadImageButton">Import Images</button>
    <div id="imageContainer"></div>
    <script>
      document.getElementById('loadImageButton').addEventListener('click', () => {
        document.getElementById('imageInput').click();
      });
    
      document.getElementById('imageInput').addEventListener('change', (event) => {
        let files = Array.from(event.target.files);
        const imageContainer = document.getElementById('imageContainer');
        imageContainer.innerHTML = '';
    
        console.log('Before Sort: ', files);
    
        // Sort files alphabetically by name
        files.sort((a, b) => a.name.localeCompare(b.name));
    
    
        console.log('After Sort: ', files);
    
    
        files.forEach(file => {
          if (file.type.startsWith('image/')) {
            const reader = new FileReader();
            const img = document.createElement('img');
            img.alt = file.name; // Use file name as alt text
            imageContainer.appendChild(img);
    
            reader.onload = (e) => {
              img.src = e.target.result;
              console.log('Image as appended: ', img);
            };
    
            reader.readAsDataURL(file);
          }
        });
      });
    </script>