-1

I have a project where the user selects images through an input element of type files and the selected images are appended in a container, but if, on a file upload that isn't the first, the files are the same as the ones before, the 'change' event listener doesn't trigger.

Here is the code for it:

function readURL(file) {
    return new Promise(function(resolve, reject) {
        let fr = new FileReader();

        fr.onload = function() {
            resolve(fr.result);
        }

        fr.onerror = function() {
            reject(fr);
        }

        fr.readAsDataURL(file);
    });
}

document.querySelector("#file").addEventListener("change", function(event) {
    let files = event.currentTarget.files;
    let readers = []

    if (!files.length) return;

    for (let i=0; i<files.length; i++) {
        readers.push(readURL(files[i]));
    }
    readers.reverse();

    Promise.all(readers)
        .then(function(values) {
            values.forEach(item => {
                let image = document.createElement("img");
                image.className = "imgs";
                image.src = item;
                document.querySelector("#messages").appendChild(image);
            });
        })
        .catch(function(err) {
            console.log(err);
        });
}, false);
body {
  width: 100vw;
  height: 100vh;
  margin: 0;
  display: grid;
  grid-template-columns: 1fr 4fr;
  grid-template-rows: 100vh;
  overflow: hidden;
}

.contacts {
  grid-column: 1 / span 1;
  background-color: darkslategray;
}

body > div {
  grid-column: 2 / span 2;
  grid-template-rows: 6fr 1fr;
  display: grid;
  grid-template-rows: 6fr 1fr;
}

#messages {
  padding: 0 20px 10px 0;
  display: flex;
  flex-direction: column-reverse;
  align-items: flex-end;
  overflow-x: hidden;
  overflow-y: scroll;
}

#text {
  background-color: brown;
  padding: 3px 5px;
}

.interact {
  background-color: darkgray;
  display: flex;
  justify-content:center;
  align-items: center;
}

#btn {
  background-color: cadetblue;
  width: 50px;
  height: 50px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 30px;
  font-weight: bold;
  border-radius: 50%;
  cursor: pointer;
}

.imgs {
  max-height: 300px;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="style.css">
    <script src="script.js" defer></script>
    <title>Document</title>
</head>
<body>
    <div class="contacts"></div>
    <div>
        <div id="messages">
        </div>
        <div class="interact">
            <div id="btn" onclick="document.getElementById('file').click()"> + </div>
        </div>
    </div>
    <input type="file" accept="image/*" id="file" multiple>
</body>
</html>

Here is a jsfiddle version as well.

Konstei
  • 55
  • 7
  • When selecting the second file are you overwriting the first? – Pedro P. Camellon Oct 02 '22 at 09:20
  • @PedroP.Camellon no, all the files are appended to the container, the ones that were uploaded already remain there – Konstei Oct 02 '22 at 09:23
  • I was able to upload several images. I really do not understand your issue. Can you give me an example? Several images at a time, as well as one by one – Pedro P. Camellon Oct 02 '22 at 10:33
  • @PedroP.Camellon no, the problem is not that multiple images cannot be uploaded at once, as that i know is possible, but rather that if you upload the same batch of images twice, for eg. [img1, img2, img3] and then [img1, img2, img3], which is the same set of images, it doesn't work; please tell me if i'm being unclear in the actual question, but i'd like to kindly ask of you to carefully read the posted question first, as i mentioned the fact that this is the problem i'm facing – Konstei Oct 02 '22 at 11:03
  • I get the same. You said: "file_input.addEventListener('change', ...) doesn't respond to the second file select" and I double check it is responding. The issue, I think, has to do with ```Promise.all(readers) .then(function(values) { values.forEach(item => { // this is skipped when loading same img twice }); })```. When I inspect `readers` items, I get an array of Promises. Maybe there is some uniqueness thing with Promises. Sorry, I don't know much about them, but I'm on it now. – Pedro P. Camellon Oct 02 '22 at 11:52
  • If you upload img1 then img2 then img1, it works, but img1 twice does not. – Pedro P. Camellon Oct 02 '22 at 12:04
  • @PedroP.Camellon well i thought the problem was with the promises or with the filereader object at first, but after adding a `console.log(0)` at the beginning of the event listener callback to make sure the input change was even registered, it didn't appear when i tested for the problem – Konstei Oct 02 '22 at 12:05
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/248509/discussion-between-pedro-p-camellon-and-konstei). – Pedro P. Camellon Oct 02 '22 at 14:15
  • Well, selecting the same file again obviously is no _change_ of what file is selected. You can clear the value of the file field after processing the file so that any new selection is again a change compared to "no file selected". – CherryDT Oct 02 '22 at 14:26
  • @CherryDT in the time i was away from this question i realized that the problem was the fact that there was no change, now that i came to edit my question it seems it's already been closed; that link does resolve my problem, but i didn't realize the root of the problem so i didn't know to search for emptying the value of the input – Konstei Oct 02 '22 at 17:01

1 Answers1

-1

This was already answered here. I would do this:

const file = document.querySelector("#file");

file.addEventListener("change", function(event) {
    let files = event.currentTarget.files;
    let readers = []

    if (!files.length) return;

    for (let i=0; i<files.length; i++) {
        readers.push(readURL(files[i]));
    }
    readers.reverse();

    Promise.all(readers)
        .then(function(values) {
            values.forEach(item => {
                let image = document.createElement("img");
                image.className = "imgs";
                image.src = item;
                document.querySelector("#messages").appendChild(image);
            });
        })
        .catch(function(err) {
            console.log(err);
        });

    // input element reset
    file.value = "";

}, false);