skip to Main Content

I feel like I’m losing my mind trying to solve this problem. I’m a fairly new web developer (this is like my third real project) and I’m trying to create a one-page application with image upload functionality. I have been using AJAX for front-end/back-end communication, so my first question would be is it possible to send images using AJAX? I’ve heard some people say it is and some say it isn’t, without a ton of detail as to why, or if it is, how.

I’ve been looking into other ways to do this and have found very little that actually contained enough detail/context to implement. I’ve managed to get something that techically works using a basic HTML form and the multer npm package, which looks like this:

editModal.innerHTML =   "<img class='thumbnail' src='" + response[0].image_loc + "'><br>" +
                        "<form method='post' action='/upload' enctype='multipart/form-data' id='edit_post_form'>" +
                        "   Select a new thumbnail<input type='file' id='post_thumbnail' name='file'><br>" +
                        "   Title<input type='text' id='post_title' name='title' value='" + response[0].title + "'><br>" +
                        "   Description<input type='text' id='post_desc' name='description' value='" + response[0].description + "'><br>" +
                        "   Price<input type='text' id='post_price' name='price' value='" + response[0].price + "'><br>" +
                        "   <button type='submit' class='submit' id='submit_post_edit'>Submit</button>" +
                        "   <button type='button' class='cancel' id='cancel_post_edit'>Cancel</button>" +
                        "</form>";
app.post('/upload', upload.single("file"), function(req, res) {

    const tempPath = req.file.path;
    const targetPath = path.join(__dirname, "./Assets/Images/image.png");

    console.log(req.file);

    if (path.extname(req.file.originalname).toLowerCase() === "png"
        || path.extname(req.file.originalname).toLowerCase() === "jpg") {

        fs.rename(tempPath, targetPath, function(err) {

            if (err) res.status(400).send({status: "Failure Internal server error"});
            else res.status(200).send({status: "Success"});
        });
    }
    else {
        fs.unlink(tempPath, function(err) {

            if (err) res.status(400).send({status: "Failure Internal server error"});
            else res.status(403).send({status: "Failure Internal server error"});
        })
    }
})

The problem is that this implementation, predictably, redirects the user off the page to the JSON file being returned. Is there any way around this? I have see some suggest writing an .onsubmit function that returns false, and using some sort of JQuery to send the file in that function. I have an .onsubmit function that I’m using to send the text fields directly to the database, and I tried returning false from it and it still redirects, so I feel stuck there as well.

form.onsubmit = function() {

    var title = document.getElementById("post_title").value;
    var description = document.getElementById("post_desc").value;
    var price = document.getElementById("post_price").value;

    $.ajax({
        url: "DBRequest",
        type: "POST",
        async: false,
        data: { data:
                JSON.stringify(
                { query: "UPDATE post SET title = $1, description = $2, price = $3 WHERE pid = $4",
                  vars: [title, description, price, postID],
                  type: "update"})}
    }).done(function(response) {
        document.body.removeChild(document.getElementById("post_edit_modal"));
        populate();
    });

    return false;
}

If the answer to both of the questions is no, then how is this generally done? And is there some place where I can read in detail about how this process works? It seems very common.

2

Answers


  1. Chosen as BEST ANSWER

    Okay, for anyone else having this problem, here's a general solution I've managed to put together using AJAX:

    HTML:

    <input type='file' id='file' name='file'>
    <button type='button' class='submit' id='submit'>Submit</button>
    

    Client-side JS:

    submit = document.getElementById("submit");
    
    submit.onclick = function() {
    
        var fileData = $("#file").prop("files")[0];
        var formData = new FormData;
        formData.append("file", fileData);
    
        $.ajax({
            url: "upload",
            dataType: "text",
            cache: false,
            contentType: false,
            processData: false,
            data: formData,
            type: "POST",
        }).done(function(response) {
            //Handle success
        }).catch(function(err) {
            //Handle error
        });
    }
    

    Server-side JS:

    let multer = require("multer");
    
    const upload = multer({ dest: "/Images" });
    
    app.post('/upload', upload.single("file"), function(req, res) {
    
        const tempPath = req.file.path;
        const targetPath = path.join(__dirname, "./Assets/Images/" + req.file.originalname);
    
        if (path.extname(req.file.originalname).toLowerCase() === ".png"
            || path.extname(req.file.originalname).toLowerCase() === ".jpg") {
    
            fs.rename(tempPath, targetPath, function(err) {
    
                if (err) res.status(400).send({status: "Failure: Internal server error"});
                else res.status(200).send({status: "Success"});
            });
        }
        else {
            fs.unlink(tempPath, function(err) {
    
                if (err) res.status(400).send({status: "Failure: Internal server error"});
                else res.status(403).send({status: "Failure: Internal server error"});
            })
        }
    })
    

    This will upload a single file to Assets/Images if the file is jpg or png.


  2. I think this is what you’re looking for. Preventing the form from reloading the page or taking you anywhere.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search