What is the best way to display multiple files in a vertical stack when choosing a file?

<div class="selected-file-container align-items-center justify-content-between d-none">
  <div class="selected-file d-flex align-items-center">
     <img id="selectedImage" class="hidden" src="" alt="Selected Image"/>
     <span id="selectedFileName">Filename.jpg</span>
  </div>
  <span>1 MB</span>
</div>
<input type="file" id="fileInput" style="display: none" />
<label for="fileInput" class="choose-file-btn">
  <span>Choose File</span>
</label>

Creating an image selection button using HTML and Bootstrap along with the ability to show an icon next to the selected image name.

<script>
  document.getElementById("fileInput").addEventListener("change", function (event) {
    const selectedFile = event.target.files[0];
    const selectedImageElement = document.getElementById("selectedImage");
    const selectedFileNameElement = document.getElementById("selectedFileName");
    const selectedFileContainer = document.querySelector(".selected-file-container");
    if (selectedFile) {
      const imageIconElement = document.createElement("i");
      imageIconElement.className = "fa-regular fa-image";
      selectedFileNameElement.innerHTML = "";
      selectedFileNameElement.appendChild(imageIconElement);
      selectedFileNameElement.insertAdjacentHTML("beforeend", selectedFile.name);
      selectedImageElement.src = URL.createObjectURL(selectedFile);
      selectedFileContainer.classList.remove("d-none");
      selectedFileContainer.classList.add("d-flex");
    } else {
        // Hide selected-file-container if no file is selected
        selectedFileContainer.classList.remove("d-flex");
        selectedFileContainer.classList.add("d-none");
      }
  });
</script>

The script involves selecting an image, adding an image icon to the selectedFileContainer, displaying only the selected image name, not the image itself.

The desired functionality is when a new image is selected, it should be listed below the previous image in separate selected-file-containers. Each new selection adds a new container under the existing list of images, creating a block layout above the button.

https://i.sstatic.net/sppTC.png

https://i.sstatic.net/AwLRJ.png

Currently, when different images are selected, only the name changes within the same container. The goal is to display each selected image name in individual containers stacked vertically one after the other.

Answer №1

organize each file into its own designated container

document.getElementById("fileInput").addEventListener("change", function (event) {
    const files = event.target.files;
    const filesContainer = document.getElementById("filesContainer");

    for (const file of files) {

        const fileContainer = document.createElement("div");
        fileContainer.className = "selected-file-container align-items-center justify-content-between d-flex";

        const fileDisplay = document.createElement("div");
        fileDisplay.className = "selected-file d-flex align-items-center";

        const imageIconElement = document.createElement("i");
        imageIconElement.className = "fa-regular fa-image";

        const fileNameElement = document.createElement("span");
        fileNameElement.textContent = file.name;

        fileDisplay.appendChild(imageIconElement);
        fileDisplay.appendChild(fileNameElement);
        fileContainer.appendChild(fileDisplay);


        filesContainer.appendChild(fileContainer);
    }


    event.target.value = '';
});
<div id="filesContainer"></div>

<input type="file" id="fileInput" style="display: none" multiple />
<label for="fileInput" class="choose-file-btn">
    <span>Choose File</span>
</label>

Answer №2

To simplify the process, you can enclose your .selected-file-container within a template tag. Then, clone it and insert the necessary file data before appending it to a container.

const showUploadedFiles = (event) => {
  const filesList = event.target.files;
  const container = document.getElementById("file-container");
  const template = document.getElementById("file");
  
  for (file of filesList) {
    const fileTemplate = template.content.cloneNode(true);
    
    fileTemplate.getElementById("selectedImage").src = URL.createObjectURL(file);
    fileTemplate.getElementById("selectedFileName").textContent = file.name;
  
    container.appendChild(fileTemplate);
  }
}

document.getElementById("fileInput").addEventListener("change", showUploadedFiles);
.choose-file-btn {
  cursor: pointer;
}

img {
  height: 25px;
}
<template id="file">
 <div class="selected-file-container align-items-center justify-content-between d-none">
    <div class="selected-file d-flex align-items-center">
       <img id="selectedImage" class="hidden" src="" alt="Selected Image"/>
       <span id="selectedFileName">Filename.jpg</span>
    </div>
    <span>1 MB</span>
  </div>
</template>

<input type="file" id="fileInput" multiple style="display: none" />
<label for="fileInput" class="choose-file-btn">
  <span>Choose File</span>
</label>

<div id="file-container"></div>

Answer №3

If you wish to include more than one image, it is advisable to avoid using <img> in the HTML code. Each new image added will alter the src attribute of the existing <img> tag in the HTML structure. Hence, every time you add a new image, you should create a fresh <img> element. Below are the correct JS and HTML codes for reference:

JS

document
.getElementById("fileInput")
.addEventListener("change", function (event) {
    const selectedFile = event.target.files[0];

    const selectedImageElement =
        document.getElementById("selectedImage");
    const selectedFileNameElement =
        document.getElementById("selectedFileName");
    const selectedFileContainer = document.querySelector(
        ".selected-file-container"
    );

    if (selectedFile) {
        const imageIconElement = document.createElement("i");
        const image = document.createElement("img");
        image.innerHTML = `<img
            id="selectedImage"
            class="hidden"
            src=""
            alt="Selected Image"
        />`
        image.src = URL.createObjectURL(selectedFile);
        
        imageIconElement.className = "fa-regular fa-image";
    
        selectedFileNameElement.appendChild(image);
        selectedFileNameElement.insertAdjacentHTML(
            "beforeend",
            selectedFile.name
        );

        selectedImageElement.src = URL.createObjectURL(selectedFile);
        selectedFileContainer.classList.add("d-flex");
    } else {
        // Hide the selected-file-container if no file is chosen
        selectedFileContainer.classList.add("d-none");
    }
});

HTML

<div class="selected-file-container align-items-center justify-content-between d-none">
    <div class="selected-file d-flex align-items-center">
        <span id="selectedFileName">Filename.jpg</span>
    </div>
    <span>1 MB</span>
</div>
<input type="file" id="fileInput" style="display: none" />
<label for="fileInput" class="choose-file-btn">
    <span>Choose File</span>
</label>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Seeking assistance in identifying the highest value in JavaScript (excluding the use of the max method)

Greetings and thank you for stopping by. I'm new to Javascript and currently facing an issue that I could use some help with. I am trying to identify the highest number from a set of variables using conditional statements within a function, but I seem ...

Struggling to construct a project using parcel, continually encountering issues with unsupported file types

My attempt at creating a project using parcel has hit a snag. Despite diligently following the guidelines provided in my assignment, an error message consistently appears in my terminal each time I initiate the command: parcel src/index.html The error mes ...

Retrieving information from a database using PHP PDO to populate a dropdown list

On my HTML page, I have a form that allows users to insert data into the database. Some fields in the form require dropdown lists, and I want to populate these dropdowns with data from the database. Previously, I had hardcoded the dropdown options like th ...

`Using top-level await in a module can interfere with the firing of the `onload` event

It seems that the load event is not triggering when I use await for an IndexedDB opening at the top level within an indirectly loaded module. Interestingly, if I remove the await, the load handler works as expected. Similarly, replacing the openDB call wi ...

A technique, such as regular expressions, can be used to detect the quantity of newline characters in the text entered by the user in a text area

I'm trying to figure out how to count the number of newline characters (or whatever is inserted when the user presses the return key) in a textarea's value. I believe I should be using a regular expression for this task, but I'm not very ski ...

I am looking to dynamically alter the CSS background URL using JavaScript

Currently, I am looking to update the background image url using JavaScript. Most tutorials I've come across involve having the image downloaded on the desktop and then providing its path. However, in my scenario, the user will input an image link whi ...

Discover the method for inserting a title attribute value into a span element

Utilizing AngularJS to retrieve and display data within a span element. I am now aiming to utilize this value as the title for another span element. The current code being used is shown below: <span style="display: inline-block; width: 160px">{{acti ...

Struggling with rendering components in REACT?

I'm encountering an issue with rendering the Butcher Shop component. I can't seem to pinpoint what's causing it to be null or undefined. Can someone help me identify the mistake? Nothing is showing up on the DOM and I keep getting this error ...

Why does my text keep drifting towards the left edge?

After spending a day learning CSS and HTML, I decided to recreate a website from a YouTube video and add my own customizations. I was able to center the text in my introduction successfully. However, upon reviewing my progress (see screenshot here), it is ...

Guide on altering the cell's background hue depending on its value through javascript

I'm dealing with a table that has 3 columns: field1 is a Category field2 and field3 contain Measures (specifically integers 1, 2, 3, 4, and 5). Is there a way to use Javascript to conditionally format the background color of cells in the table hol ...

Is there a way for me to implement this code to achieve the functionality shown in the demo link

$('select').change(function() { var sum = 0; var sum = parseInt($('select[name="bathrooms"]').val() * 25) + parseInt($('select[name="bedrooms"]').val() * 8); $("#sum").html(sum); }); <script src="https://ajax.googleap ...

How can I create automated tests for a Vue.js Tailwind CSS application using Cypress?

As I review the Cypress.io docs, I notice that the examples on how to write tests heavily rely on class selectors. However, my TailwindCSS application consists of numerous small classes rather than the specific ones mentioned in the examples, making it cha ...

Tips for implementing jQuery overlay to display radio buttons in a popup window

Following a tutorial, I created an alert window with radio buttons added for user input. You can view the online demo here. The modified source code with the radio buttons is provided below. Below you'll find where I added the radio buttons and how I ...

Tips for accessing various JSON objects from a JSON document

My task involves extracting specific information from a JSON file using AJAX and jQuery. The structure of my JSON data is as follows: "Footwear": { "Adidas": [ { "id" : 0, &q ...

Ways to identify mouse clicks on three.js sprite

I am trying to implement a click event detection on a three.js sprite using the following code: function bindEvents(state) { let intersected; function onDocumentMouseDown(event) { event.preventDefault(); const mouseX = (event.clientX / window. ...

The act of binding is not functioning

Hello everyone, I am excited to be posting on stackoverflow for the first time. Recently, I have started learning ember.js and I am really enjoying it. Currently, I am working on a small project to practice my ember.js skills, but I seem to be having tro ...

Positioning a box at the bottom rather than at the top

I am on the lookout for a solution to shift/arrange divs to the bottom instead of the top. For example, when attempting to delete some of the divs with the "box" class in this code snippet: Current code: #hol ...

Using JavaScript to modify the text of a label seems to be a challenging

UPDATE: After carefully reviewing my code once again, I have identified the issue. The problem lies in the positioning of a certain function (unfortunately not included here), but rest assured that I have rectified it! Allow me to provide a brief summary ...

Is there a way to assign multiple paths to a single page within the NextJS pages directory?

I'm currently working on a project that has two different themes, and I have the ability to switch between them based on the environment. Everything works perfectly, but I'm encountering an issue with paths. Some pages should open with different ...

utilize jQuery to load webpage with an HTML dropdown element

Querying the Campaigns: // Getting the campaigns $campaigns = $wpdb->get_results( "SELECT * FROM tbl_campaigns ORDER BY campaignID DESC", OBJECT_K ); // Displaying the Cam ...