biccs
biccs

Reputation: 147

Form POST request, not working. Undefined in Server (HTML,JS,EXPRESS,NODE,MONGODB)

Im working in an application with a front and a back end, my back end written in nodejs, using express, multer and mongoose, is working pretty fine when i send data through postman, but as soon as i try the same request in my client made with html,css and vanilla javascript, it doesnt work, it gives me the following error:

TypeError: Cannot read property 'path' of undefined (which is pointing towards my network file that manages connections for a specific entity).

Despite the error mentioned above, i've been trying to send a file and a string from the form in html to the network file in my node server, but i keep getting the same 2 or so errors in terminal.

Here is some code so you can understand better.

server.js (main entry point)

const express = require('express');
const app = express();
const server = require('http').Server(app);
const path = require('path');

const cors = require('cors');
const bodyParser = require('body-parser');
const db = require('./db');
const router = require('./network/routes');
const config = require('./config');

db(config.dbUrl);
app.use(cors());
app.use(express.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.use(`${config.publicRoute}`, express.static(path.join(__dirname, 'public')));
server.listen(config.port, function() {});
console.log(`Application listen on ${config.host}${config.port}`);
router(app);

network.js (file that manages connections for "banner" entity)

const express = require('express');
const multer = require('multer');
const router = express.Router();
const response = require('../../network/response');
const controller = require('./controller');
const path = require('path');
const storage = multer.diskStorage({
    destination: function(req, file, cb) {
        cb(null, path.join(__dirname, '../../public/files'))
    },
    filename: function(req, file, cb) {
        cb(null, path.extname(file.originalname))
    }
})
const upload = multer({ storage: storage })

router.post('/', upload.single('file'), function(req, res) {

    console.log(req.body);
    controller.addBanner(req.body.name, req.file, req.file.path)
        .then((fullMessage) => {
            response.success(req, res, fullMessage, 201);
        })
        .catch(e => {
            response.error(req, res, 'Unexpected error', "Simulated Error", 400, e);
        });
});

router.get('/', function(req, res) {
    controller.getBanners()
        .then((banners) => {
            response.success(req, res, banners, 200);
        })
        .catch(e => {
            response.error(req, res, 'Internal Error', 500, e);
        })
});

router.delete('/:id', function(req, res) {
    controller.deleteBanner(req.params.id)
        .then(() => {
            response.success(req, res, `Imagen con id: ${req.params.id} ,eliminada`, 200);
        })
        .catch(e => {
            response.error(req, res, 'Internal Error', 500, e);
        })
});

module.exports = router;

panel.html (where the form that supposedly sends the post request lies)

<!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">
    <!-- <meta http-equiv="Content-Security-Policy" content="default-src https://cdn.example.net; child-src 'none'; object-src 'none'"> -->
    <link rel="stylesheet" type="text/css" href="css/panel-style.css">
    <script defer src="panel-script.js"></script>
    <title>Panel de Control</title>
</head>

<body>
    <header>
        <img src="assets/mrvapeslogo.png" alt="mrvapes logo">
        <a href="index.html"></a>
    </header>
    <section>
        <form accept-charset="UTF-8" enctype="multipart/form-data" action="../components/banner/network.js" autocomplete="off" method="GET" target="_blank">
            <label for="user">Banners Activos</label><br/>
            <ul class="files-container">

            </ul>
        </form>
        <form accept-charset="UTF-8" enctype="multipart/form-data" action="http://localhost:3000/banner" autocomplete="off" method="POST" target="_blank">
            <div class="container">
                <div class="button-wrap">
                    <!-- <label class="button" for="upload">Subir</label> -->
                    <input type="text" id="name" placeholder="Nombre de Archivo" value="" name="name" required>
                    <input id="image" value="Subir" placeholder="Subir Archivo" type="file" required>
                    <button id="upload" name="send-post--request" value="post-request" type="submit">Enviar</button>
                    <!-- <input id="upload" type=" submit " value="Enviar " onclick="submit() "> -->
                </div>
            </div>
        </form>
    </section>
</body>

panel-script.js (client-side file that manages the logic for the http request)

const upload = document.getElementById("upload");
const image = document.getElementById("image");
const title = document.getElementById("name");

upload.addEventListener("click", (e) => {
    console.log('im in bro');
    e.preventDefault();
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            alert(xhr.response);
        }
    }
    xhr.open("POST", 'http://localhost:3000/banner', true);
    //xhr.setRequestHeader("Accept", "multipart/form-data");
    //xhr.setRequestHeader('Content-Type', 'multipart/form-data');
    var fileSent = {
        "name": title,
        "file": image
    };
    console.log(fileSent);
    xhr.send(fileSent);
    alert('Subida exitosa!');
})


function retrieve() {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
            alert(xhr.response);
        }
    }
    xhr.open('get', 'http://localhost:3000/banner', true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
    xhr.send();
}

I'm all ears towards your suggestions, thanks in advance fellow developers.

Upvotes: 0

Views: 1225

Answers (2)

DSander
DSander

Reputation: 1124

You need to provide the name for the <input type="file">. It must match upload.single('file').

<input id="image" name="file" value="Subir" placeholder="Subir Archivo" type="file" required>

In Express 4 req.file is no longer available on the req object by default. I see you are using multer middleware to handle that. The error is likely coming from multer in network.js when you try to access req.file.path. The req.file is undefined because upload.single('file') is looking for form data named file, and you don't have name="file" in the form input.

-EDIT-

I see now you are not trying to send the file with the native HTML Form submit (which should work now with my answer), and you are listening to submit button clicks to send with XMLHttpRequest in panel-script.js. Sending a multipart/form-data with XMLHttpRequest is only supported with XHR FormData API (which is only available to new browsers). See the answer here if you wish to continue with using panel-script.js: Send a file as multipart through XMLHttpRequest

In your case you would have to use:

var formData = new FormData();
formData.append("file", document.getElementById("image").files[0]);

var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:3000/banner");
xhr.send(formData);

Upvotes: 3

biccs
biccs

Reputation: 147

Just solved the problem, adding to the response i got from fellow DSander, i actually needed to put the name to my html tag, and i dont know if its right but what solved the problem is deleting the script tag in my html so it doesnt use the send method i wrote.

Commented this

<script defer src="panel-script.js"></script>

and stopped using panel-script.js

Upvotes: 0

Related Questions