0

I created one web service using node js. Using this service, I want to select user information and a photo from the react user interface and save them to mongodb. But The name of the photo is saved in Mongodb, but the photo is not saved under the directory ./public/uploads/. What should I do to fix this error? Node js and react just started learning. I share the codes I wrote below with you.

Model

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

newSchema = new Schema({
    name : String,
    email : String,
    password : String,
    img: String
})

module.exports = mongoose.model('User', newSchema)

Routes

const express = require('express')
const User = require('../models/index')
const router = express.Router()
const multer = require('multer')

var imgStorage = multer.diskStorage({
    destination: './public/uploads/',
    filename:(req, file, cb)=>{
        cb(null, file.fieldname+"_"+Date.now()+path.extname(file.originalname))
    }
})

var upload = multer({
    storage: imgStorage
}).single('file')


/* create new*/
router.post('/', upload, (req,res)=>{
    user = new User({
        name:req.body.name,
        email:req.body.email,
        password:req.body.password,
        img: req.body.img
    })

    user.save(()=>{
        res.json(user)
    })
})

/* find all users */
router.get('/', (req, res) => {
    User.find({},(err,data) =>{
        res.json(data)
    })
})

/* find user by id */
router.get('/:id',(req, res) =>{
    User.findById(req.params.id, (err, data) =>{
        res.json(data)
    })
})

/* delete user by id */
router.delete('/:id',async (req, res) =>{
    await User.findByIdAndDelete(req.params.id)
    res.json({'message':'deleted'})
})

/* update */
router.put('/:id', async (req, res)=>{
    await User.findByIdAndUpdate(req.params.is, req.body)
    res.json({'message':'updated'})
})

module.exports = router

Index

const express = require('express');
const mongoose = require('mongoose');
const mongodb = require('mongodb');
const cors = require('cors');
mongoose.connect('mongodb://localhost:27017/admin?authSource=$[authSource] --username $[username]', {useNewUrlParser : true});
const app = express();

app.use(express.json())
app.use(cors())
app.use(express.urlencoded({extended:true}))

app.use('/api',require('./routes/index'))

const port = process.env.PORT || 8080

app.listen(port)

module.exports =  new mongoose.model('User', newSchema)

React side

import React, {Component} from 'react';
import axios from 'axios';

class App extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            users: [],
            id: 0,
            name: '',
            email: '',
            password: '',
            img: ''
        }
    }

    componentDidMount() {
        try {
            axios.get('http://localhost:8080/api')
                .then((res) => {
                    this.setState({
                        users: res.data,
                        id: 0,
                        name: '',
                        email: '',
                        password: '',
                        img: ''
                    })
                })
        } catch (e) {
            console.log(e)
        }
    }

    nameChange = event => {
        this.setState({
            name: event.target.value
        })
    }

    emailChange = event => {
        this.setState({
            email: event.target.value
        })
    }

    passwordChange = event => {
        this.setState({
            password: event.target.value
        })
    }

    fileSelectedHandler = event =>{
        this.setState({
            img : event.target.files[0]
        })
    }

    submit(event, id) {
        event.preventDefault()
        if (id === 0) {
            // const fd = new FormData();
            // fd.append('image', this.state.img, this.state.img.name);
            axios.post('http://localhost:8080/api', {
                name: this.state.name,
                email: this.state.email,
                password: this.state.password,
                //img: this.state.img
                img : this.state.img.name
            }).then(()=>{
                this.componentDidMount()
            })

        } else {
            axios.put('http://localhost:8080/api/'+id, {
                name: this.state.name,
                email: this.state.email,
                password: this.state.password,
                img: this.state.img
            }).then(()=>{
                this.componentDidMount()
            })
        }
    }

    deleteUser(id) {
        try {
            axios.delete('http://localhost:8080/api/' + id)
                .then((res) => {
                    this.componentDidMount()
                })
            console.log('Deleted successfully.')
        } catch (e) {
            console.log(e)
        }
    }

    editUser(id) {
        try {
            axios.get('http://localhost:8080/api/' + id)
                .then((res) => {
                    console.log(res.data)
                    this.setState({
                        id:res.data._id,
                        name: res.data.name,
                        email: res.data.email,
                        password: res.data.password
                    })
                })
        } catch (e) {
            console.log(e)
        }
    }

    render() {
        return (
            <div className="row">
                <div className="col s6">
                    <form onSubmit={(e) => this.submit(e, this.state.id)}>
                        <div className="input-field col s12">
                            <i className="material-icons prefix">person</i>
                            <input value={this.state.name} onChange={(e) => this.nameChange(e)} type="text" id="autocomplete-input"
                                   className="autocomplete" required/>
                            <label htmlFor="autocomplete-input">Name</label>
                        </div>
                        <div className="input-field col s12">
                            <i className="material-icons prefix">mail</i>
                            <input value={this.state.email} onChange={(e) => this.emailChange(e)} type="email" id="autocomplete-input"
                                   className="autocomplete" required/>
                            <label htmlFor="autocomplete-input">Email</label>
                        </div>
                        <div className="input-field col s12">
                            <i className="material-icons prefix">vpn_key</i>
                            <input value={this.state.password} onChange={(e) => this.passwordChange(e)} type="password" id="autocomplete-input"
                                   className="autocomplete" required/>
                            <label htmlFor="autocomplete-input">Password</label>
                        </div>
                        <div className="input-field col s12">
                            <input type="file" name="file" onChange={(e) => this.fileSelectedHandler(e)}/>
                        </div>
                        <br/>
                        <button className="btn waves-effect waves-light right blue" type="submit" name="action">Submit
                            <i className="material-icons right">send</i>
                        </button>
                    </form>
                </div>
                <div className="col s6">
                    <table>
                        <thead>
                        <tr>
                            <th>Name</th>
                            <th>Email</th>
                            <th>Password</th>
                            <th>IMG</th>
                            <th>Edit</th>
                            <th>Delete</th>
                        </tr>
                        </thead>
                        <tbody>
                        {this.state.users.map(user =>
                            <tr key={user._id}>
                                <td>{user.name}</td>
                                <td>{user.email}</td>
                                <td>{user.password}</td>
                                <td>
                                    <img src="./public/uploads/user.img.name" width="80"/>
                                </td>
                                <td>
                                    <button onClick={(e) => this.editUser(user._id)}
                                            className="btn waves-effect waves-light green" type="submit" name="action">
                                        <i className="material-icons right">edit</i>
                                    </button>
                                </td>
                                <td>
                                    <button onClick={(e) => this.deleteUser(user._id)}
                                            className="btn waves-effect waves-light red" type="submit" name="action">
                                        <i className="material-icons right">delete</i>
                                    </button>
                                </td>
                            </tr>
                        )}
                        </tbody>
                    </table>
                </div>
            </div>
        );
    }

}

export default App;

2 Answers 2

1
    You have to send file inside formData to the server like 
    inside submit function. Then send fd to server

          const formData = new FormData();
                formData.append('image', this.state.img);
     formData.append('name', this.state.name);
     formData.append('password', this.state.password);
     formData.append('password', this.state.email);

axios.post('/yourEndpoint', formData).then(res => {
  //Now do what you want with the response;
})
Sign up to request clarification or add additional context in comments.

11 Comments

How can I post formdata with other fields (name, password, email)? Also, how do I add the odsya path I have set. So I want the file to be added to the directory I have specified.
Check below rply
change destination to destination: 'public/uploads' this and i sent another rply the that cant comment here because it long,
I will test your last shared code tomorrow. it made sense to me. Do I need to install npm for "const path = require ('path')"? Do I need to make another change, for example, on the react side?
Yeah install that and change your sumbit function in react side according to upper rply send it as form data
|
0

put this code in you route file and change name of below endpoint .hope it will works.Ask if you are not clear

var multer = require('multer');
    var path = require('path')
    var storage = multer.diskStorage({
        destination: function (req, file, cb) {
            cb(null, 'public/uploads')
        },
        filename: function (req, file, cb) {
            cb(null, Date.now() + path.extname(file.originalname)) //Appending extension
        }})
    var upload = multer({ storage: storage });
    router.post('/', upload.single('image'), (req,res)=>{

        if (req.file.filename) {
               req.body.image = req.file.filename;
            }
        user = new User({
            name:req.body.name,
            email:req.body.email,
            password:req.body.password,
            img: req.body.image
        })
    })

2 Comments

You didn't use FormData, I didn't understand it here
I used form data.. see my previous reply. okkey see below reference stackoverflow.com/a/61033681/10309265 this is for react end submit function. And upper code is for nodeJS end. If you sent form data/or whatever data from react end you will get those in req.body in node end. Let me knq otherwise i will give full code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.