Client side
Add the html for an input control that accepts file images
src/user/EditProfile.js
1 2 3 4 5 6 7 8 9 10 11 12 13 |
renderEditForm = (name, email, password) => { return (<form> <div className="form-group"> <label className="text-muted">Profile Photo</label> <input onChange={this.handleChange("photo")} type="file" accept="image/*" className="form-control" /> </div> ... } |
Basically, we need to send the form data to the backend.
We need to use browser API called FormData
FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values.
We update our handleChange to reflect responding to photo file clicks.
src/user/EditProfile.js
1 2 3 4 5 |
handleChange = name => event => { const value = name === 'photo' ? event.target.files[0] : event.target.value this.userData.set(name, value) this.setState({ [name] : value }) } |
We need to change our body so that we’re sending the formData, and not a string.
We also need to remove the Content-Type headers because its not json anymore. Its key/value formData
src/user/apiUser.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
export const UpdateUser = async (userId, token, user) => { console.log(`UpdateUser, '1) update user info for user id: ${userId} using token ${token}` ) console.log('User Data update:', user) return await fetch(`http://localhost:8080/user/${userId}`, { method: "PUT", mode: "cors", headers: { Accept : "application/json", // "Content-Type": "application/json", // for non-image values // we're sending formData, not json data Authorization: `Bearer ${token}`, 'Access-Control-Allow-Origin':'*' }, // for non-image values // body: JSON.stringify(user) // remember to json stringify this or else, server side can't receive such data // for images, we're sending formData body: user }) .then(response => { console.log('UpdateUser', '3) response received') return response.json() }) .catch(err => { return err }) } |
Now, refresh the page and try sending a photo, for the PUT request, look at your FormData, you should see all the data there.
Server side
We comment out the previous updateUser function and write a new one.
controllers/user.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
const _ = require('lodash') const User = require('../models/user'); const formidable = require('formidable') const fs = require('fs') ... ... exports.updateUser = (req, res, next) => { let form = new formidable.IncomingForm() form.keepExtensions = true form.parse(req, (err, fields, files) => { if (err) { return res.status(400).json({ error: "Photo could not be uplaoded" }) } // save user let user = req.profile user = _.extend(user, fields) user.updated = Date.now() if (files.photo) { user.photo.data = fs.readFileSync(files.photo.path) user.photo.contentType = files.photo.type } user.save( (err, result) => { if (err) { return res.status(400).json({ error: err }) } user.hashed_password = undefined user.salt = undefined res.json(user); }) }) } |
Now, try to upload the photo.