How to Upload File from angular7 to Node.js server - node.js

My node.js code is working 100% by Postman,
but in angular when I send a FormData and nothing happened in server, no error but the file not uploaded.
how can i upload file by angular?
HTML Compnent:
<form>
<input type="file" (change)="OnFileSelected($event)" name='photo'>
<button type='submit' (click)="OnUpload()">Save Post</button>
</form>
Ts Compnent:
OnFileSelected(event){
this.SelectedFile = event.target.files[0] as File;
}
OnUpload(){
const form: FormData = new FormData();
form.append('photo', this.SelectedFile, this.SelectedFile.name);
//Convert to Json because 'Unexpected token - in JSON at position 0 at JSON.parse' error in server
let responseBody: {} = JSON.stringify(form);
this.http.post(URL, responseBody).subscribe(event => { console.log(event)}, err => {console.log(err)
});
}
Node.js Server:
const path = require('path');
const express = require('express');
const multer = require('multer');
const bodyParser = require('body-parser')
const router = express.Router();
const DIR = './uploads';
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, DIR);
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
let upload = multer({ storage: storage });
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: true }));
router.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');
res.setHeader('Access-Control-Allow-Methods', 'POST');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
router.post('/upload-image', upload.single('photo'), async function (req, res) {
console.log(req.body);
if (!req.file) {
console.log("No file received");
return res.send({
success: false
});
} else {
console.log('file: ',req.file);
return res.send({
success: true
})
}
});

You need to specify that your Request is a form-data request:
// Create Form Data
const formData: FormData = new FormData();
formData.append('photo', this.SelectedFile, this.SelectedFile.name);
// Create options for the request
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'multipart/form-data', // <-- IMPORTANT
'Accept': 'application/json'
})
};
this.http.post(URL, formData, httpOptions).subscribe(...)

There are many ways to transfer file to the server, if it's a common scenario, then I will suggest using Dropzone.js angular wrapper.
Better have a custom angular component with all the custom configuration of Dropzone to meet your needs.
Using it is also quite easy, once you have installed the package, file input is as simple as follow:
<dropzone [config]="config" [message]="'Click or drag images here to upload'"
(error)="onUploadError($event)" (success)="onUploadSuccess($event)"></dropzone>
Documentation can be found here:
https://www.npmjs.com/package/ngx-dropzone-wrapper

You need to first instantiate your file in OnInit() before creating an instance in your OnUpload() function which you have done:
ngOnInit() {
this.form = new FormGroup({
photo: new FormControl(null, {
validators: [Validators.required]}) }
You can remove the validators if you like, you can also edit your onFileSelected() function like this:
this.SelectedFile = event.target.files[0] as File;
this.form.patchValue({ photo: file });
this.form.get('photo').updateValueAndValidity();
const reader = new FileReader();
reader.readAsDataURL(file);
console.log(file);
call your function like this:
onUploadFile(event: Event){}

Related

How to upload a file using Multer in a specific directory defined by the frontend in vuejs

I want to upload a file using Multer in a specific directory in my NodeJs app defined by the frontend in vuejs.
It is my first application with multer
The backend code is :
...
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
//req.body.idUser is undefined here
let destinationPath = path.join("upload_file", req.body.idUser);
if (!fs.existsSync(destinationPath)) {
fs.mkdirSync(destinationPath);
}
cb(null, destinationPath);
},
filename: (req, file, cb) => {
let newFileName = Date.now() + path.extname(file.originalname);
cb(null, newFileName);
},
});
const upload = multer({ storage });
app.post(
"/file/add",
upload.fields([{ name: "newfile" }, { name: "idUser" }]),
(req, res) => {
res.json({
response: "file uploaded",
});
},
);
...
And the frontend code is :
...
async sendDocument(event){
const file = event.target.files[0]
const form = new FormData()
form.append("newfile", file, file.name)
form.append("idUser", this.getIdUser)
const opts =
{
method: "POST",
body: form,
}
const url = "http://localhost:3000/file/add";
try{
await fetch(url, opts)
.then(function (response) {
return response.json();
})
.then(function (res) {
console.log(res)
});
}catch(err){
console.log(err)
}
},
...
I tried to debug step by step with console.log to check why req.body.idUser is not defined in storage and I need it to complete the destinationPath
If I replace req.body.idUser by static value like "toto", all work fine
In front, this.getIdUser is working fine. And req.body.idUser is working in app.post
Thanks for your help
Try appending the ID to the form first:
const form = new FormData()
form.append("idUser", this.getIdUser)
form.append("newfile", file, file.name)

facing some issue uploading file and data with multer in express server

I have 2 problems. I am trying to upload an excel file to the server when I upload an excel file I got the file on my console log but the file is not saving into the folder which I declared on my storage variable.
// Middleware
app.use(express.json())
app.use(cors());
app.use(fileupload());
app.use(express.static("files"));
app.use(bodyParser.json({ limit: "50mb" }));
app.use(bodyParser.urlencoded({ limit: "50mb", extended: true, parameterLimit: 50000 }));
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
var upload = multer({ storage: storage })
File upload API. The 2nd problem is I have sent some data and a file from frontend. I am getting the file only but on my req.body I got undefined. If I remove the upload.single('file') then I got the other data.
app.post("/upload-excel", upload.single('file'), async (req, res) => {
const vendor = req.body
const file = req.files.file;
const filename = file.name;
console.log(vendor);
})
Here is my frontend:
const ProductImport = function () {
const [file, setFile] = useState<any>();
const [isLoading, setIsLoading] = useState<boolean>(false);
const [fileName, setFileName] = useState("");
const { userDetails } = UseAuth()
const saveFile = (e) => {
setFile(e.target.files[0]);
setFileName(e.target.files[0].name);
};
const uploadFile = async (e: any) => {
e.preventDefault()
const formData = new FormData();
formData.append("file", file);
formData.append("fileName", fileName);
formData.append("vendor", userDetails.role);
formData.append("store", userDetails.store);
formData.append("publisher", userDetails.email);
fetch('http://localhost:5000/upload-excel', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.insertedId) {
alert('excel Added')
}
})
.catch(error => {
console.error('Error:', error);
});
};
return (
<form onSubmit={uploadFile}>
<label htmlFor="formGroupExampleInput" className="form-label">Example label</label>
<input type="file" onChange={saveFile} />
<button type="submit">Upload</button>
</form>
)
}
backend folder structure

Multer react + node js unable to get req.file

Hi I am trying to upload a file from fronend to backend using multer
Front End
var formData = new FormData();
formData.append("files", image[0]);
formData.append("data", JSON.stringify({status: 'ACK', message: "You are fu*ked"});
return http.axios
.post(apiUrl + apiDomain + "/createAnnouncement", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((res) => res);
Backend
const bodyParser = require("body-parser");
const Express = require("express");
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, config.get("announcemnt_upload_file_storage"));
},
filename: function (req, file, cb) {
cb(null, file.filename + "_" + Date.now());
},
});
var upload = multer({ storage: storage });
const Router = Express.Router();
Router.route("/createAnnouncement").post(
upload.single("files"),
(req , resp, next) => {
console.log(" >>>>>>>", req.file);//THis returns undefined
console.log(">>>>", req.files);//This returns undefined
resp.send("Siccess")
}
);
Below is my Req snapshot
Its not getting uploaded to storage and its returning undefined when called req.file
But if I try to see req.body I could see [Object File] in console
PLease suggest where I am going wrong
I think this may help https://github.com/RUSHI-GADHIYA/uploading-and-updating-image see this

Multiparty file upload issue with body parser using angularjs and nodejs [duplicate]

This question already has an answer here:
AngularJS Upload Multiple Files with FormData API
(1 answer)
Closed 3 years ago.
Trying to upload a file from Angularjs UI to nodejs server but facing issues with bodyparser, adding limit to it throws -
"SyntaxError: Unexpected token - in JSON at position 0",
if limit not added throws -
"Payload too large"
I am using connect-multiparty middleware to upload the file. Tried with {limit: '50mb'} in bodyparser and without any limit as well.
UI Code -
$('#imgupload').on('change', function (evt) {
let uploadedFiles = evt.target.files;
let formData = new FormData();
for (var i = 0; i < uploadedFiles.length; i++) {
formData.append("uploads[]", uploadedFiles[i],
uploadedFiles[i].name);
}
let url = "/upload";
httpService.restApi(url,formData)
.then(function (response) {
console.log("the file has been uploaded to local server
",response);
});
});
Nodejs (server code)-
const multipart = require('connect-multiparty');
const multipartMiddleware = multipart({ uploadDir: './uploads' });
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({extended: true}));
app.post('/upload', multipartMiddleware, (req, res) => {
res.json({
'message': 'File uploaded succesfully.'
});
});
Remove the bodyParser middleware from the path:
const multipart = require('connect-multiparty');
const multipartMiddleware = multipart({ uploadDir: './uploads' });
̶a̶p̶p̶.̶u̶s̶e̶(̶b̶o̶d̶y̶P̶a̶r̶s̶e̶r̶.̶j̶s̶o̶n̶(̶{̶l̶i̶m̶i̶t̶:̶ ̶'̶5̶0̶m̶b̶'̶}̶)̶)̶;̶
̶a̶p̶p̶.̶u̶s̶e̶(̶b̶o̶d̶y̶P̶a̶r̶s̶e̶r̶.̶u̶r̶l̶e̶n̶c̶o̶d̶e̶d̶(̶{̶e̶x̶t̶e̶n̶d̶e̶d̶:̶ ̶t̶r̶u̶e̶}̶)̶)̶;̶
app.post('/upload', multipartMiddleware, (req, res) => {
res.json({
'message': 'File uploaded succesfully.'
});
});
The contents is application/form-data, not application/json or application/x-www-form-urlencoded.
If you use multer and make the API call using $http explicitly setting the "Content-Type" header to multipart/form-data you will get "Multer: Boundary not found error" and if you remove the "Content-Type" header or set it to false it throws - "Converting circular structure to JSON error". Hence i used "fetch" to make the API call as it automatically identified the "Content-Type".
UI Code (modified as below) -
$('#imgupload').unbind('change').on('change', function (evt) {
evt.stopPropagation();
evt.preventDefault();
let uploadedFiles = evt.target.files;
let formData = new FormData();
for(let i=0; i<uploadedFiles.length;i++){
formData.append("uploads", uploadedFiles[i], uploadedFiles[i].name);
}
let url = '/upload';
var req = {
method: 'POST',
body: formData
}
fetch(url,req).then(function(response) {
console.log("the file has been uploaded to local server ",response);
$scope.uploadToSftp();
});
});
Nodejs Code (modified as below) -
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './uploads/')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
const multipartMiddleware = multer({ storage: storage });
app.use(bodyParser.json({limit: '50mb'}));
app.use(bodyParser.urlencoded({
extended: true
}));
app.post('/upload', multipartMiddleware.array("uploads",2), function(req, res)
{
console.log("the upload api is called");
return res.send(req.files);
});

Sending file from one node js server to another

So on first server I have route like this:
const express = require('express');
const router = express.Router();
const FormData = require('form-data');
const fetch = require('node-fetch');
const multer = require('multer');
const storage = multer.memoryStorage();
const upload = multer({ storage });
router.post('/', upload.single('file'), async (req, res) => {
const form = new FormData();
form.append('folderId', req.body.folderId);
form.append('file', req.file.buffer, req.file.filename);
const result = await fetch('http://localhost:3003/users', { method: 'POST', body: form }).then(res => res.json());
res.json(result);
})
On this server, it works fine, I can see req.file and it's buffer. So I wanna send this file (without storing it on first server, it exists only in memory and as buffer) to another.
Other server route is like this:
const express = require('express');
const router = express.Router();
const multer = require('multer');
const path = require('path');
const putanja = path.join(__dirname, '../uploads/users');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
console.log('entered here?')
if (!req.body.folderId) return cb({ message: 'no folderId' });
if (!fs.existsSync(putanja + '/' + folderId)) fs.mkdirSync(putanja + '/' + folderId);
cb(null, putanja + '/' + folderId);
},
filename: (req, file, cb) => cb(null, file.originalname)
});
const upload = multer({ storage });
const fs = require('fs');
router.post('/', upload.single('file'), async (req, res) => {
console.log(req.body)
console.log(req.file)
res.json({ status: 'ok' })
})
So on second server, it doesn't even enter the multer middleware, req.file is always defined, and that console.log('entered here?') is never seen. Looks like I'm not passing data as multipart-form?
Also, second server, when sending file directly to it via postman, works.
So my question, how do I send that file? As a buffer? Stream? Base64? I think I tried everything, even changed node-fetch to request, but still no luck.
So on second server, it doesn't even enter the multer middleware, req.file is always defined, and that console.log('entered here?') is never seen. Looks like I'm not passing data as multipart-form?
So this mean your second server doesn't understand the Content-Type of request.
So do one thing add Content-Type parameter in header when you are sending request to second server
Add Content-Type to multipart/form-data
or if you don't know pass headers : {
'Content-Type' : undefined
} http will set header for you
You send your request to /users (http://localhost:3003/users) yet your second server expects the request on /.
Try changing either one to match the other.
'use strict';
const express = require('express');
const multer= require('multer');
const concat = require('concat-stream');
const request = require('request');
const router = express.Router();
function HttpRelay (opts) {}
HttpRelay.prototype._handleFile = function _handleFile (req, file, cb) {
console.log('hell0 proto');
file.stream.pipe(concat({ encoding: 'buffer' }, function (data) {
const r = request.post('/Endpoint you want to upload file', function (err, resp, body) {
if (err) return cb(err);
req.relayresponse=body;
cb(null, {});
});
const form = r.form();
form.append('uploaded_file', data, {
filename: file.originalname,
contentType: file.mimetype
});
}))
};
HttpRelay.prototype._removeFile = function _removeFile (req, file, cb) {
console.log('hello');
cb(null);
};
const relayUpload = multer({ storage: new HttpRelay() }).any();
router.post('/uploadMsgFile', function(req, res) {
relayUpload(req, res, function(err) {
res.send(req.relayresponse);
});
});
module.exports = router;

Resources