3

I am creating a blog so, wanted to upload an image for each post. I used express-file upload for this purpose. Using nodejs I have done the following to save the image sent from the client-side in MongoDB. When I print the value of req.files in the console I get undefined.

exports.addPost = (req, res) => {
    const file = req.files.file
    const post = new Blog()
    post.title = req.body.title
    post.des = req.body.des
    post.file = file
    post.save((err, doc) => {
        if (!err) {
            res.send(doc)
        } else {
            console.log(err)
        }
    })
}

In react I have Addpost.js that sets the state and handles the form submit as follows:

const Addpost=()=> {
    const [title, settitle] = useState('')
    const [des, setdes] = useState('')
    const [file, setfile] = useState('');
    
    const {addPost}=useContext(Globalcontext)
    
    const handleSubmit = (e)=>{
        e.preventDefault()
        const formData = new FormData()
        formData.append('file',file)
        const addedValue={
            title,
            des,
            formData
        }
        addPost(addedValue)
        settitle('')
        setdes('')
        setfile('')
    }
    
    const onChange=(e)=>{
        const file=e.target.files[0]
        setfile(file)
    }
    
    return (
        <div>
            <form onSubmit={handleSubmit} encType="multipart/form-data">
                <input type="text" name="title" value={title} onChange={(e)=>settitle(e.target.value)}/>
                <input type="text" name="des"value={des} onChange={(e)=>setdes(e.target.value)}/>
                <input type="file" name="file" onChange={onChange}/>
                <button type='submit' value='submit'>Add Post</button>
            </form>
        </div>
    )
}

The AXIOS post request is sent as:

function addPost(postdetail) {
    axios.post('http://localhost:4000/blog', postdetail).then(res => {
        dispatch({
            type: 'ADD_DATA',
            payload: res.data
        })
    }).catch(error => {
        console.log(error)
    })
}

I am getting the error:

Cannot read property 'file' of undefined
Paul Rumkin
  • 6,737
  • 2
  • 25
  • 35
Smriti Shrestha
  • 129
  • 1
  • 2
  • 6
  • Does this answer your question? [How do you use express-fileupload correctly](https://stackoverflow.com/questions/62672111/how-do-you-use-express-fileupload-correctly) – Vijay Palaskar Jul 14 '20 at 11:14
  • on the React side, i'd recommend a library like react-uploady. it makes it very easy to send additional headers/parameters – poeticGeek Jul 14 '20 at 13:30

1 Answers1

3

1. Probably you didn't register middleware.

According to the doc example, you should register express-fileupload middleware before you refer req.files:

const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();

// default options
app.use(fileUpload());

Also don't forget to add null check in case when no files are uploaded:

app.post('/upload', function(req, res) {
  if (!req.files || Object.keys(req.files).length === 0) {
    return res.status(400).send('No files were uploaded.');
  }
  let file = req.files.file;
  // do something with uploaded temp file
}

2. Content type should be multipart/form-data when you upload file

const handleSubmit=(e)=>{
e.preventDefault()
const formData=new FormData()
formData.append('file', file)
setfile('')
}

function addPost(postdetail){
  axios.post('http://localhost:4000/blog',formData, {
    headers: {
      'Content-Type': 'multipart/form-data'
    }
  }).then(res=>{
      dispatch({
        type:'ADD_DATA',
        payload:res.data
      })
      
    }).catch(error=>{ 
      console.log(error)
    })
  }

3. Other form fields(des, title) may not be submitted using multipart/formdata

Consider open two routes for blog creation.

[POST] '/blog/upload-image' for image upload

[POST] '/blog/new for create blog (title, des and image_id acquired from image upload response)

glinda93
  • 7,659
  • 5
  • 40
  • 78
  • If I use two post methods will I be able to add title and description as well as images from the same form? – Smriti Shrestha Jul 14 '20 at 12:43
  • `uploadImages().then(resp => { const imagesIds = resp.data; saveBlog(title, desc, imagesIds));` – glinda93 Jul 14 '20 at 13:25
  • and the app.use(fileUpload()) should be placed before anything else, just after the declaration of app. I had it after app.use(cors()) and after app.use(express.json()) and it did not work. – BertC Mar 11 '22 at 14:13