i am trying very hard to upload file but no way i could find a clear solution .
i have tried many ways but not working . Now the console shows me 200 and give me message that file is uploaded but file is not going in the folder . i ahve checked file size limit and folder is ok but dont know why its not working. could any help please.
///react component
import { saveBasicUser, getOneBasicUser, uploadFile } from
'../../actions/basicAction';
this.state = { file: []};
handleChange(event) {
this.setState({
[event.target.name]: event.target.value,
file:
event.target.files})
}
handleSubmit(event) {
event.preventDefault();
var file = this.state.file
let formData = new FormData();
formData.append('file', file);
// console.log(obj);
console.log(formData);
// this.props.dispatch(saveBasicUser(obj ))
this.props.dispatch(uploadFile(formData ))
}
<form onSubmit={this.handleSubmit} encType="multipart/form-data">
<input type="file" name = "file" onChange={this.handleChange} />
<button type="submit" className="btn btn-success btn-lg">Submit</button>
////////action part
export function uploadFile(formData) {
console.log(formData)
return (dispatch) => {
return axios.post('/upload_file', {
headers: { 'content-type': 'multipart/form-data' },
data: formData
}).then(function (res) {
console.log(res)
}).catch(function (err) {
console.log(" err")
console.log(err)
})
}
}
//////server part
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now()+ path.extname(file.originalname))
}
})
var upload = multer({ storage: storage, limits: {fileSize : 1000000} }).single('file');
app.post('/upload_file', function(req, res){
upload(req, res, function(err) {
if(err) {
return res.end("Error uploading file.");
}
res.end("File is uploaded");
});
});
I have found the solution at last.
react JS
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import Messages from '../Messages';
import classnames from 'classnames';
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
import { getOneBasicUser ,uploadFile} from '../../actions/basicAction';
//--------------------------------------------------------------------------
class Upload extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
};
this.handleChange = this.handleChange.bind(this);
this.handleFile = this.handleFile.bind(this);
}
//--------------------------------------------------------------------
//--------------------------------------------------------------------------
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
//--------------------------------------------------------------------------
handleFile(e) {
e.preventDefault();
var id = this.props.params.id;
console.log(id);
var formData = new FormData($('form')[0]);
var isFileExist = !!$('input[type=file]')[0].files[0];
if (isFileExist) {
$.ajax({
url: '/upload_file/'+ id,
type: 'POST',
data: formData,
xhr: function () {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function (e) {
if (e.lengthComputable) {
$('progress').attr({value: e.loaded, max: e.total});
$('#status').empty().text(parseInt((e.loaded / e.total * 100)) + '%');
}
}, false);
return xhr;
}.bind(this),
success: function (data) {
this.setState({
data: data
});
$('#status').empty().text('File Uploaded!');
}.bind(this),
error: function (xhr, status, err) {
console.log( err);
}.bind(this),
cache: false,
contentType: false,
processData: false
});
} else {
$('#status').empty().text('Please choose the file.');
}
}
//--------------------------------------------------------------------------
render() {
return (
<div className="container ca-container">
<div className="row">
<div className="col-md-12">
<h2> Upload File </h2>
<hr />
</div>
</div>
<form onSubmit={this.handleFile} encType="multipart/form-data">
<div className="row">
<div className="col-md-12">
<div className="col-md-6">
<h3 id="status" className ="label label-success"></h3>
<div className="form-group">
<label>
Name:
</label>
<input type="file" className="form-control" name="BasicUserFile" onChange={this.handleChange} placeholder="file" />
</div>
<div className="btn-group" role="group">
<button type="submit" value="Upload File" className="btn btn-success btn-lg">Upload</button>
</div>
</div>
</div>
</div>
</form>
</div>
);
}
}
// ======================== REDUX CONNECTORS ========================
const mapStateToProps = (state) => {
return {
//basicUser: state.basicUser.basicUser
};
};
export default connect(mapStateToProps)(Upload);
////server.js
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './uploads')
},
filename: function (req, file, cb) {
var basic_id = req.params.id
cb(null, file.fieldname + '-' + basic_id+ path.extname(file.originalname))
}
})
var upload = multer({ storage: storage, limits: {fileSize : 1000000} }).single('BasicUserFile');
app.post('/upload_file/:id', function(req, res){
console.log("000000000000000000000000000000000000000000000000")
console.log(req.params)
console.log("000000000000000000000000000000000000000000000000")
upload(req, res, function(err) {
if(err) {
return res.end("Error uploading file.");
}
res.end("File is uploaded");
});
});
Related
I am trying to upload an image for a blog posts using Multer. I am using mongodb and NodeJS for the backend and Angular for the front end. Whenever I perform the POST request and check in the console, the req.file is always undefined. I have tried using Multer's upload.any() with req.files and req.files[0].filename but to no avail. I have no clue why it stays undefined.
Here's my Multer Code:
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public');
},
filename: (req, file, cb) => {
console.log(file);
var filetype = '';
if(file.mimetype === 'image/gif') {
filetype = 'gif';
}
if(file.mimetype === 'image/png') {
filetype = 'png';
}
if(file.mimetype === 'image/jpeg') {
filetype = 'jpg';
}
cb(null, 'file-' + Date.now() + '.' + filetype);
}
});
const upload = multer({storage: storage, limits: { fieldSize: 10 * 1024 * 1024 } });
Here's the Server POST request:
router.post('/newPost', passport.authenticate('jwt', { session: false}), upload.single('image'), function(req, res, next) {
console.log(req.file);
let newPost = new Post({
postTitle: req.body.postTitle,
postAuthor: req.body.postAuthor,
postImgUrl: 'http://localhost:3000/public/' + req.file.filename,
postContent: req.body.postContent
});
Post.create(newPost, (err, user) => {
if(err) {
res.json({success: false, msg: 'Post failed to submit'});
} else {
res.json({success: true, msg: 'Successfully Posted'});
}
});
});
This is my Angular Service for the POST request:
addPost(post): Observable<post> {
this.loadToken();
const head = this.headers.append("Authorization", this.authToken);
return this.http.post<post>(this.baseUri + "/newPost", post, { headers: head });
}
This is my TypeScript Component code:
export class BlogAddComponent implements OnInit {
postTitle: '';
postAuthor: '';
postContent: '';
postImgUrl: string;
post: any[] = [];
postForm: FormGroup;
public editor = Editor;
config;
constructor(private postService: PostService,
private formBuilder: FormBuilder,
private router: Router,
private flashMessage: FlashMessagesService) {
}
onFileSelect(event: Event) {
const file = (event.target as HTMLInputElement).files[0];
this.postForm.patchValue({ image: file });
const allowedMimeTypes = ["image/png", "image/jpeg", "image/jpg"];
if (file && allowedMimeTypes.includes(file.type)) {
const reader = new FileReader();
reader.onload = () => {
this.postImgUrl = reader.result as string;
};
reader.readAsDataURL(file);
}
}
ngOnInit(): void {
this.postForm = new FormGroup({
postTitle: new FormControl(null),
postAuthor: new FormControl(null),
postContent: new FormControl(null),
postImgUrl: new FormControl(null)
});
}
onBlogSubmit() {
this.postService.addPost(this.postForm.value).subscribe(
data => {
this.flashMessage.show('Blog Submitted Successfully', {cssClass: 'alert-success', timeout: 3000});
this.router.navigate(['/blog-page']);
},
error => {
this.flashMessage.show('Something Went Wrong', {cssClass: 'alert-danger', timeout: 3000});
}
);
}
}
And this is my Component HTML:
<body>
<div [formGroup]="postForm" class="container" *ngIf="post">
<h1 class="mb-4">New blog post</h1>
<form [formGroup]="postForm" (ngsubmit)="onBlogSubmit()" enctype="multipart/form-data">
<div class="form-group">
<label for="postImgUrl">Image</label>
<input (change)="onFileSelect($event)" type="file" class="form-control" name="image" required>
</div>
<div class="form-group">
<label for="title">Title</label>
<input formControlName="postTitle" type="text" class="form-control" placeholder="Title" name="postTitle" required>
</div>
<div class="form-group">
<label for="author">Author</label>
<input formControlName="postAuthor" type="text" class="form-control" placeholder="Author" name="postAuthor" required>
</div>
<br>
<div class="form-group">
<ckeditor formControlName="postContent" name="postContent" [editor]="editor" [config]="config"></ckeditor>
</div>
<br>
<div class="form-group">
<a routerLink="/blog-page" class="btn btn-warning">Cancel</a>
<button type="submit" class="btn btn-primary" (click)="onBlogSubmit()">Save</button>
</div>
</form>
</div>
</body>
I am really stuck with this. Any help, pointers or guidance are greatly appreiciated. Thank You very much.
You should send formData with the name image as you configured on backend:
addPost(post): Observable<post> {
this.loadToken();
const head = this.headers.append("Authorization", this.authToken);
const formData: FormData = new FormData();
formData.append('image', post.postImgUrl);
return this.http.post<post>(this.baseUri + "/newPost", formData, { headers: head });
}
I'm not able to get the filename or path from Multer. This is what I've done so far:
uploadcsv.js
const fileUpload = multer({
limits: 500000,
storage:multer.diskStorage({
destination: (req, file, cb) =>{
cb(null,'upload/csv')
},
filename: (req, file, cb) =>{
const ext = MIME_TYPE_MAP[file.mimetype]
cb(null, uuid + '.' + ext)
},
fileFilter: (req, file, cb) =>{
const isValid = !!MIME_TYPE_MAP[file.mimetype]
let error = isValid ? null : new Error('Invalid mime type')
cb(error, isValid)
}
})
})
Then the route api:
router.post('/contact/importcontact', JWTAuthenticationToken, fileUpload.single('csv'), async (req, res) => {
console.log(req.body)
console.log(req.file.filename)
const csvFilePath = req.file.filename
const stream = fs.createReadStream(csvfile);
const account= await Account.findOne({ acctid: { "$eq": req.body.acctid } })
try {
if (req.file == undefined)
return res.status(400).send({ msg: 'No files were uploaded.' });
csvtojson()
.fromFile(csvFilePath)
.then((jsonObj) => {
console.log(jsonObj);
})
// Async / await usage
const jsonArray = await csvtojson().fromFile(csvFilePath);
res.json({ success: "Uploaded Successfully", status: 200 })
} catch (error) {
res.json({ message: error })
}
})
Lastly, the react importcustomer.js
const handleCSVChange = (e) => {
console.log(e.target.files[0])
setCsvData(e.target.files[0])
setUploadButtonData(e.target.files[0].name)
}
const uploadCSVData = async (e) => {
setLoading(true)
const formData = new FormData();
formData.append("csv", csvData);
console.log(formData)
e.preventDefault()
const response = await Axios.post(process.env.REACT_APP_FETCH_URL + '/api/contact/importcontact', { formData: formData, acctid: lsData.acctid}, { withCredentials: true })
if (response.data.statusCode === "409") {
setMessage(response.data.msg)
setLoading(false)
}
else if (response.data.statusCode === "200") {
setLoading(false)
//history.push('/sources')
}
}
return (
<div className="col-12 grid-margin stretch-card">
<div className="card">
<div className="card-body">
<h4 className="card-title">Import Customer Data From CSV</h4>
<form className="forms-sample" enctype="multipart/form-data">
<div className="form-group">
<label for="files" className="btn btn-primary">{uploadButtonData}
<input id="files" type="file" name="csv" className="form-control" hidden accept="*.csv" onChange={handleCSVChange} /></label>
</div>
<button className="btn btn-primary" onClick={uploadCSVData} style={{ float: "right", width: "7rem" }} type="button">
{loading && <i className="fa fa-refresh fa-spin"></i>}
Upload CSV</button>
<div className="mt-3" style={{ textAlign: "center" }}>
<span id="msg" style={{ color: "red" }}>{message}</span>
</div>
</form>
</div>
</div>
</div>
)
Though I'm able to console.log(req.body) and console.log(e.target.files[0]) and getting the acctid and filename but returned empty for the console.log(formData) and console.log(req.file.filename) returned undefined. What have I missed? Many thanks in advance and greatly appreciate any helps. Thanks again
I have managed to solves this by appending the acctid to formData:
const formData = new FormData();
formData.append("csv", csvData);
formData.append("accctid", lsData.acctid);
const response = await Axios.post(process.env.REACT_APP_FETCH_URL + '/api/contact/importcontact', formData, { withCredentials: true })
Depending on your viewpoint, I was able to get the most important part of getting a Avatar/Image in an app...pushing to the database (MongoDB in my case, Also the image gets added to my server folder).
However what I can't get working is the success modal to fire or the rendering of the image on the page, which is strange as the response.status === 200 and response.ok === true? I am using Multer in Express. (I am using fetch).
This is my ImageLoader component:
import React, { Component } from 'react';
import './ImageUploader.css';
import Modal from '../Modal/MyModal.jsx'
import DefaultImg from '../../static/profile-avatars/assets/default-img.jpg';
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { modalStateOn, modalStateOff } from '../../store/index'
const API_URL = "http://localhost:8016";
class ImageUploader extends Component {
constructor(props) {
super(props);
this.state = {
multerImage: DefaultImg,
}
}
setDefaultImage(uploadType) {
if (uploadType === "multer") {
this.setState({
multerImage: DefaultImg
});
}
}
uploadImage(e, method) {
var { history, isLoggedIn, modalActive, modalStateOn, modalStateOff } = this.props
let imageObj = {};
if (method === "multer") {
let imageFormObj = new FormData();
imageFormObj.append("imageName", "multer-image-" + Date.now());
imageFormObj.append("imageData", e.target.files[0]);
// stores a readable instance of
// the image being uploaded using multer
this.setState({
multerImage: window.URL.createObjectURL(e.target.files[0])
});
return window.fetch('http://localhost:8016/images/uploadmulter', {
method: 'POST',
// body: e.target.files[0]
body: imageFormObj
})
.then((response) => {
console.log("response ", response);
this.setDefaultImage("multer");
return (
<>
{response.ok && <Modal
isAlertModal={true}
history={history}
affirmativeUsed="Yes"
message="Image has been successfully uploaded!"
isLoggedIn={isLoggedIn}
modalActive={true}
modalStateOn={modalStateOn}
modalStateOff={modalStateOff}></Modal>}
</>
)
})
.then((data) => {
console.log("data ", data);
this.setDefaultImage("multer");
})
.catch(error => {
this.setDefaultImage("multer");
console.log("error ", error);
})
}
} // end upload function
render() {
// console.log("uploadImage function this.props ", this.props);
return (
<div className="main-container">
<h3 className="main-heading">Image Upload App</h3>
<div className="image-container">
<div className="process">
<h4 className="process__heading">Process: Using Multer</h4>
<p className="process__details">Upload image to a node server, connected to a MongoDB database, with the help of multer</p>
<form action="/uploadmulter" method="post" encType="multipart/form-data" >
<input type="file" name="avatar" className="process__upload-btn" onChange={(e) => this.uploadImage(e, "multer")} />
<img src={this.state.multerImage} alt="upload-image" className="process__image" />
</form>
</div>
</div>
</div>
);
}
}
function mapStateToProps(state) {
const { isLoggedIn, modalActive } = state
return { isLoggedIn, modalActive }
}
const mapDispatchToProps = dispatch =>
bindActionCreators({ modalStateOn, modalStateOff }, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(ImageUploader)
And this is the route on my express server server/images/index.js:
var router = require('express').Router();
var Image = require('../models/Image');
var multer = require('multer')
var storage = multer.diskStorage({
destination: function(req, file, cb){
cb(null, './server/uploads/');
},
filename: function(req, file, cb){
cb(null, Date.now() + file.originalname)
}
})
var fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
// rejects storing a file
cb(null, false)
}
}
var upload = multer({
storage: storage,
limits : {
fileSize : 1024 * 1024 * 5
},
fileFilter: fileFilter
})
router.route('/uploadmulter')
.post(upload.single('imageData'), (req, res, next) => {
console.log('req.body', req.body);
var newImage = new Image({
imageName: req.body.imageName,
imageData : req.file.path
})
newImage.save()
.then(result => {
res.status(200).json({
success: true,
document:result
})
})
.catch(err=> next(err))
});
module.exports = router
So to reiterate why doesn't the image render and modal fire when the response is true or 200?
I'm trying to save images from my react app to backend using nodejs(express) and multer, I tried from these How to upload image using javascript fetch api and express multer
after I got the message file uploaded, how do you store it to database?
Here's the code in my react app
class UploadCover extends React.Component {
constructor(props){
super(props);
this.state={
id: this.props.location.state.id,
selectedFile : '',
imagePreviewUrl: ''
}
}
//handle image change
handleImageChange = (e) => {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () =>{
this.setState({
selectedFile:file,
imagePreviewUrl: reader.result
});
};
reader.readAsDataURL(file);
this.handleUploadCover(e.target.files[0]);
}
//upload cover
handleUploadCover = (file) => {
let form = new FormData(this.refs.myForm);
form.append('myImage', file);
fetch('http://localhost:3001/upload-cover', {
method: 'post',
header: { "Content-Type" : "application/json"},
body: form
})
.then( res =>res.json())
.then(data => console.log("data: ", data))
};
render() {
const { classes, ...rest } = this.props;
const { id, imagePreviewUrl } = this.state;
console.log("url: ", imagePreviewUrl)
let $imagePreview = null;
if(imagePreviewUrl){
$imagePreview = <img style={{width: "100%", height: "100%"}} src={imagePreviewUrl}/>;
}else{
$imagePreview = (
<div className={classes.previewText}>Please select cover</div>
);
}
return (
<div>
<HeaderHome/>
<div className={classNames(classes.main, classes.mainRaised)}>
<div className={classes.container}>
<div className={classes.storymargin}>
<h2 className={classes.title}>Upload Cover Story</h2>
<Card className={classes.uploadcontainer}>
<CardContent>
<div className={classes.imgPreview}>{$imagePreview}</div>
<form ref='myForm' encType='multipart/form-data'>
<input
accept="image/*"
className={classes.input}
id="raised-button-file"
multiple
type="file"
onChange={ e => this.handleImageChange(e)}
// ref='myForm'
/>
</form>
<label htmlFor="raised-button-file">
<Button component="span" className={classes.buttonupload}>
Choose Image
</Button>
</label>
</CardContent>
<CardActions>
<Link
to={{
pathname: "/create-chapter",
state: {id : id}
}}
>
<Button size="small" clor="primary" className={classes.buttonnextup}
onClick={ e => this.handleUploadCover(e) }
>
Next
</Button>
</Link>
</CardActions>
</Card>
</div>
</div>
</div>
<div className={classes.footer}>
<Footer />
</div>
</div>
);
}
}
and here's the backend
//set storage engine
const storage = multer.diskStorage({
destination: './public/uploads',
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
})
//Init upload
const upload = multer({
storage: storage,
limits: {fileSize: 1000000},
fileFilter: (req, file, cb) => {
checkFileType(file, cb);
}
}).single('myImage');
//Check File Type
checkFileType = (file, cb) => {
//Allowed ext
const filetypes = /jpeg|jpg|png|gif/;
//Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
//Check mime
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null, true);
}else{
cb('Error: Images Only');
}
}
//upload cover story
app.post('/upload-cover', (req, res) => {
console.log('handling upload image');
upload( req, res, (err) => {
if(err){
console.log('first err', err);
res.send({
msg: err
});
}else{
if(req.file === undefined){
console.log('Error: No File Selected');
res.send({
msg: 'Error: No File Selected'
});
}else{
console.log('File Uploaded');
res.send({
msg: 'File Uploaded',
file: `uploads/${req.file.filename}`
});
}
}
});
});
and how can i send request with content type application/json and multipart/form-data at the same time through body request, I want to send form and id:this.state.id
console.log giving this but file is not uploading
{
name:"sds",
shop_name:"dfgdfg",
address:"hfgdhf",
phone:"dfgfgd",
file:"C:\fakepath\favicon.png",
…
}account_status:"pending"address:"hfgdhf"backup_database:""expiry:"2017-10-19"file:"C:\fakepath\favicon.png"name:"sds"phone:"dfgfgd"shop_name:"dfgdfg"__proto__:{
data:"File is uploaded",
status:200,
statusText:"OK",
headers:{
…
},
config:{
…
},
…
}
component.js
import { saveBasicUser, getOneBasicUser, uploadFile } from '../../actions/basicAction';
class BasicUser extends React.Component {
constructor(props) {
super(props);
this.state = { name: '', phone: '', account_status: '', address: '', shop_name: '', file: [], backup_database: '', expiry: '' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
//--------------------------------------------------------------------------
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
//--------------------------------------------------------------------------
handleSubmit(event) {
event.preventDefault();
var userId = this.props.params.id;
var obj = {};
obj["name"] = this.state.name
obj["shop_name"] = this.state.shop_name
obj["address"] = this.state.address
obj["phone"] = this.state.phone
obj["file"] = this.state.file
obj["backup_database"] = this.state.backup_database
obj["expiry"] = this.state.expiry
obj["account_status"] = this.state.account_status
console.log(obj)
this.props.dispatch(saveBasicUser(obj))
}
<form onSubmit={this.handleSubmit} encType="multipart/form-data">
<div className="row">
<div className="col-md-12">
<div className="form-group">
<label>
Name:
</label>
<input type="text" className="form-control" name="name" value={this.state.name} onChange={this.handleChange} placeholder="Zahid Hasan" /> .......................................
..........................................
</div>
<div className="form-group">
<label>File Upload</label>
<div className="form-group">
<label>File Upload</label>
<input type="file" className="form-control" name="file"value={this.state.file}b onChange={this.handleChange} />
</div>
</div>
<div className="btn-group" role="group">
<button type="submit" className="btn btn-success btn-lg">Submit</button>
</div>
action.js
export function saveBasicUser(obj) {
console.log(obj)
return (dispatch) => {
return axios.post('/basic-user/saveUser', {
headers: { 'content-type': 'multipart/form-data' },
obj: obj
}).then(function (res) {
browserHistory.push('/basic-dashboard');
console.log(res)
}).catch(function (err) {
console.log(" err")
console.log(err)
})
}
}
server.js
var multer = require('multer')
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './public/uploads')
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now()+ path.extname(file.originalname))
}
})
var upload = multer({ storage: storage, limits: {fileSize : 1000000} }).single('file')
app.post('/basic-user/saveUser',function(req,res){
upload(req, res, function(err) {
if(err) {
return res.end("Error uploading file.");
}
res.end("File is uploaded");
});
});
only way to upload file via ajax is use FormData try this.
handleSubmit(event) {
event.preventDefault();
var userId = this.props.params.id;
let formData = new FormData();
formData.append('name', this.state.name);
...
formData.append('file', this.state.file);
...
this.props.dispatch(saveBasicUser(obj))
}
And action file
export function saveBasicUser(obj) {
return (dispatch) => {
return axios.post('/basic-user/saveUser', obj).then(function (res) {
browserHistory.push('/basic-dashboard');
console.log(res)
}).catch(function (err) {
console.log(" err")
console.log(err)
})
}
}
I think you have not created proper destination to upload your image file at server side.
Please check your destination is exist /public/uploads in your server working dir.
Following links will help you on file upload functionality ,
Uploading files with React.js and Node.js
Sample Demo Code
Hopes this will help you !