javascriptnode.jsexpressvisual-studio-codenodemon

how to prevent page reload after file upload


I wrote some code to provide image upload function. After uploading, the html page should show the image name of the uploaded file.

HTML CODE:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>test</h1>
    <form id="uploadForm">
        <input type="file" id="myFiles" accept="image/*" multiple />
        <button>Submit</button>
    </form>
    <h2></h2>
    <script>
        const form = document.getElementById("uploadForm")
        const sendFiles = async () => {
            const myFiles = document.getElementById("myFiles").files
            const formData = new FormData()
            Object.keys(myFiles).forEach(fk => {
                console.log("%%%%%%%%", Object.keys(myFiles), fk, typeof (fk))
                formData.append(myFiles.item(fk).name, myFiles.item(fk))
            })
            const res = await fetch("http://127.0.0.1:3500/upload", {
                method: "POST",
                body: formData
            })
            const json = await res.json()
            const h2 = document.querySelector("h2")
            h2.textContent = `message:${json?.message}`
        }

        form.addEventListener("submit", (ev) => {
            ev.preventDefault()
            sendFiles()
        })
    </script>
</body>

NODE JS CODE:

const express = require("express")
const path = require("path")
const fileUpload = require("express-fileupload")
const app = express()
const PORT = process.env.PORT || 3500
const cors = require("cors")

app.use(cors())
app.get("/", (req, res) => {
    res.sendFile(path.join(__dirname, "index.html"))
})
app.post("/upload",
    fileUpload({ createParentPath: true }),
    (req, res) => {
        const file = req.files
        Object.keys(file).forEach(k => {
            const fileP = path.join(__dirname, "uploadFolder", file[k].name)

            file[k].mv(fileP, (e) => {
                if (e) return res.status(500).json({ status: "err!!!!!", message: e })
            })
        })

        return res.json({ message: Object.keys(file).toString() })
    })

app.listen(PORT, () => { console.log(`listen on port ${PORT}`) })

I uploaded an image "cookie_screenshot" and submitted it. The html showed the name just for a sec and the page reloaded immediately. How to make the name always displayed on screen?

I use express 4.21.1\nodemon 3.1.7\vs code.

BEFORE SUBMIT: enter image description here

DISPLAY NAME FOR INSTANT: enter image description here

PAGE RELOADED IMMEDIATELY: enter image description here


Solution

  • The issue you’re experiencing is caused by the inside your form acting as a submit button by default, causing the form to trigger page reload. Although you have used ev.preventDefault() in the event listener, the form’s default behavior may not always be stopped correctly due to the button’s submit action.

    Here is the updated code:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    
    <body>
       <h1>Test</h1>
       <form id="uploadForm">
           <input type="file" id="myFiles" accept="image/*" multiple />
           <!-- Change type from 'submit' to 'button' -->
           <button type="button" id="uploadButton">Submit</button>
       </form>
       <h2></h2>
       <script>
          const form = document.getElementById("uploadForm");
          const uploadButton = document.getElementById("uploadButton");
          const sendFiles = async () => {
              const myFiles = document.getElementById("myFiles").files;
              const formData = new FormData();
              Object.keys(myFiles).forEach(fk => {
                  formData.append(myFiles.item(fk).name, myFiles.item(fk));
              });
              const res = await fetch("http://127.0.0.1:3500/upload", {
                  method: "POST",
                  body: formData,
              });
              const json = await res.json();
              const h2 = document.querySelector("h2");
              h2.textContent = `Uploaded file(s): ${json?.message}`;
          };
    
          // Attach the click event listener to the button
          uploadButton.addEventListener("click", (ev) => {
              ev.preventDefault(); // Prevent default behavior
              sendFiles();
          });
      </script>
    </body>
    </html>
    

    Let me know if that helped you out!