I would like to upload an image and a json to a server using Express and Multer.
When I test with Postman there is no problem but when I test with the Front-end in Angular, it seems that the image isn't sent.
Here are the codes :
problem-form.component.html
<div class="problemContainer">
<div class="problemForm">
<h2>Soumission de problème</h2>
<form [formGroup]="form" (ngSubmit)="submitForm()">
<p>
<mat-form-field class="inputFW">
<input matInput formControlName="User" placeholder="Adresse email">
<mat-error>This field is required</mat-error>
</mat-form-field>
</p>
<p>
<mat-form-field class="inputFW">
<input matInput value="{{machineName}}" placeholder="Nom de la machine" disabled>
<mat-error>Le nom de la machine est requis</mat-error>
</mat-form-field>
</p>
<p>
<mat-form-field class="inputFW">
<textarea matInput placeholder="Description du problème (max 200 caractères)" formControlName="Description" rows="3"></textarea>
</mat-form-field>
</p>
<p>
<label>Image (Optionnel)</label><br><br>
<input type="file" (change)="fileChange($event)" name="image" />
</p>
<button mat-raised-button color="primary">Envoyer</button>
</form>
</div>
function in the component that call the service
submitForm(){
if(this.form.valid){
let obj = this.form.value
obj.image = this.image
this.service.createProblem(obj).subscribe(data => console.log(data), err => {console.log(err)})
}else{
console.log("erreur")
}
}
function in the service that post to the server
createProblem(problem: Object){
console.log('roman')
let form = new FormData()
form.append('Name', problem['Name'])
form.append('Description', problem['Description'])
form.append('User', problem['User'])
form.append('image', problem['image'])
console.log(problem['image'])
return this.http.post(getUrl()+ `problems`, form);
}
Configuration of multer
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'images')
},
filename: function (req, file, cb) {
cb(null, 'problem_' + Date.now()+'.'+mime.extension(file.mimetype))
}
})
let upload = multer({ storage: storage });
The route that call a function in the controller
router.route('/')
/** GET /api/problems - Get list of Problems */
.get(pbCtrl.list)
/** POST /api/problem - create a new problem */
.post(/*validate(paramValidation.problem), */upload.single('image'), pbCtrl.create);
The function in the controller
function create(req, res, next) {
let photo
if(req.file != null)
photo = req.file.filename
PC.findOne({ Name: req.body.Name, Active: true }, { '_id': 0 }).exec()
.then((pc) => {
if (pc == null)
return res.sendStatus(400)
const newPc = new PC({
Name: pc.Name,
Local: pc.Local,
IP: pc.IP,
MAC: pc.MAC,
Comment: pc.Comment,
Active: pc.Active,
Problem: { User: req.body.User, Description: req.body.Description, Image: photo }
})
newPc.save()
.then(savedPC => {
res.json(savedPC);
//return next();
}).catch(e => { next(e); });;
})
.catch((err) => {
console.log(err)
res.sendStatus(400)
})
}
Thanks all
Resolved
function to load file
fileChange($event) {
let reader = new FileReader();
if($event.target.files && $event.target.files.length > 0) {
let file = $event.target.files[0];
this.file = file
}
}
function that submit the form
submitForm(){
if(this.form.valid){
let obj = this.form.value
obj.image = this.file
this.service.createProblem(obj).subscribe(data => this.openSnackBar('Votre demande a bien été enregistrée'), err => {console.log(err)})
}else{
console.log("erreur")
}
}
function in the service to post
createProblem(problem: Object){
let form = new FormData()
form.append('Name', problem['Name'])
form.append('Description', problem['Description'])
form.append('User', problem['User'])
form.append('image', problem['image'])
return this.http.post(getUrl()+ `problems`, form).map((res) => {
return res.json()
});
}
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 have a table in my database called products and I am trying to insert into in using node.js express server as the web service and react.js as the front-end language.
Below is my react.js form to perform the insertion.
function App() {
return (
<div className="container">
<form onSubmit = {(e) => Add(e)}>
<div className="form-group">
<label htmlFor="examplePname">Name</label>
<input type="text" className="form-control" id="examplePname" aria-describedby=""/>
</div>
<div className="form-group">
<label htmlFor="examplePprice">Price</label>
<input type="number" className="form-control" id="examplePprice"/>
</div>
<div className="form-group form-check">
<input type="checkbox" className="form-check-input" id="exampleCheck1"/>
<label className="form-check-label" htmlFor="exampleCheck1">Check me out</label>
</div>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
</div>
);
}
function Add(e){
e.preventDefault();
let request = {
name: document.getElementById('examplePname').value,
price: document.getElementById('examplePprice').value,
}
alert("returns this:"+ request)
axios.post('http://localhost:3000/add', request)
.then(resp => {
alert(resp.data.message);
})
.catch(err => {
console.log(err);
})
}
Below is my node.js express Webservice
router.post('/add', (req, res) => {
const {name, price} = req.query;
console.log(name, price); ///Do this before you write the insert query
//res.send('adding product');Do this before you write the insert query (add temp products to view in cmd)
const INSERT_QUERY = `INSERT INTO products (name, price) VALUES('${name}', ${price})`; //after do an insert query to add to db proper
connection.query(INSERT_QUERY, (err, results) => {
if (err) {
return res.send({
message: "failed"
})
} else {
return res.send({
message: "successful"
});
}
});
});
But when I insert I get undefined values for both name and price in console.log.
Use Below code in app.js in node side for parsing parameter
const bodyparser = require('body-parser');
const multer = require('multer');
//Multer
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './Images');
},
filename: function (req, file, cb) {
let fileType = file.originalname.split('.');
cb(null, `${fileType[0]}_${Date.now()}.${fileType[1]}`);
}
})
var upload = multer({ storage: storage });
app.use(upload.any());
// Parse
app.use(bodyparser.json({ limit: '50mb', extended: true }));
app.use(bodyparser.urlencoded({ limit: '50mb', extended: true, parameterLimit: 1000000 }));
Please install above dependencies before restart the server
React side send form data as below
createFormData(props) {
var formData = new FormData();
for (var key in props) {
if (typeof props[key] === "string" || props[key] instanceof Date) {
formData.append(key, props[key]);
}
else if (typeof props[key] === "object") {
if (Array.isArray(props[key]) && key === "file") {
//Multiple File Upload
props[key].length > 0 && props[key].forEach((element) => {
if (element.lastModifiedDate) {
formData.append(key, element);
}
})
}
else if (props[key] && props[key].lastModifiedDate) {
//Single File Upload
formData.append(key, props[key]);
} else {
formData.append(key, JSON.stringify(props[key]));
}
} else {
formData.append(key, JSON.stringify(props[key]));
}
}
return formData;
}
// Axios Request
axios({
url: url here,
method: 'POST',
data: this.createFormData(your form data object),
timeout: 30000
}).then(response => {
if (response.status === 200) {
}
})
you will get data as follow at node side
let data = { ...req.body, ...req.params, ...req.query }
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
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");
});
});
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 !