upload file in angular 2 with nodejs - node.js

I am new in angular 2 and node js.
I need to upload file in folder using anjular2 and also want to store that file name in mongodb database, at server side. For that I tried this but its not working.Using code is that:
app.component.ts:
attachment: any;
hasBaseDropZoneOver: boolean = false;
options: Object = {
url: 'http://localhost:3000/upload'
};
sizeLimit = 2000000;
handleUpload(data): void {
if (data && data.response) {
this.attachment = data;
}
}
fileOverBase(e:any):void {
this.hasBaseDropZoneOver = e;
}
beforeUpload(uploadingFile): void {
console.log(uploadingFile.size + ' -- '+this.sizeLimit);
if (uploadingFile.size > this.sizeLimit) {
uploadingFile.setAbort();
alert('File is too large');
}
}
this is app.html file:-
<input type="file" ngFileSelect [options]="options" (onUpload)="handleUpload($event)" (beforeUpload)="beforeUpload($event)">
app.module.ts
import { Ng2UploaderModule } from 'ng2-uploader';
Server Side Code:
const upload = multer({
dest: 'uploads/',
storage: multer.diskStorage({
filename: (req, file, cb) => {
let ext = path.extname(file.originalname);
cb(null, `${Math.random().toString(36).substring(7)}${ext}`);
}
})
});
app.post('/upload', upload.any(), (req, res) => {
res.json(req.files.map(file => {
let ext = path.extname(file.originalname);
return {
originalName: file.originalname,
filename: file.filename
}
}));
});
It is showing me below error:
XMLHttpRequest cannot load http://localhost:3000/upload. Response to preflight request doesn't pass access

Related

Upload Excel file via NodeJs, Multer and Angular - Uploaded Excel is transformed to zip file

I am using NodeJs with Multer to upload Excel file to the server.
I am using this to upload excel file. My Excel file is in server transformed into zip file, which is not OK.
Later in my project, I need another API, which will download that same uploaded Excel file via Angular application and it need to be Excel.
(If I upload pdf file, it stays pdf...)
NodeJs part of code:
Route:
const multer = require("multer");
const storage = multer.diskStorage({
destination: (req: any, file: any, cb: any) => {
cb(null, "utilities/uploaded-excels");
},
filename: (req: any, file: any, cb: any) => {
// dolocis ime fila
const name: string = file.originalname.toLowerCase().split(" ").join("-");
cb(null, name + "-" + Date.now());
},
});
// Upload excel file
router.patch(
"/uploadFile/:id",
multer({ storage: storage }).single("file"),
verifyToken,
containerController.uploadReportFile
);
Controller:
exports.uploadReportFile = async (req: any, res: any) => {
try {
let newExcelPath = {
newExcelPath: "./utilities/uploaded-excels/" + req.file.filename,
};
await Container.findByIdAndUpdate(req.params.id, newExcelPath, {
new: true,
}).then((container: any) => {
if (!container) {
return res.status(404).send();
}
res.status(200).json(container);
});
} catch (err) {
console.log(err);
res.status(404).json({ success: false, msg: err });
}
};
Postman exmaple:
Angular service:
uploadFile(
id: string,
file: File
): Observable<ServerResponse> {
const fileData = new FormData();
fileData.append("file", file, "title-of-file?");
const url: string = this.apiUrl + "uploadFile/" + id;
if (!this.token) {
const authString = `Bearer ${this.token}`;
httpOptions.headers = httpOptions.headers.append(
"Authorization",
authString
);
}
return this.http.patch<ServerResponse>(url, fileData, httpOptions);
}
component.ts where I upload file
onFileSelected(event: any) {
this.selectedFile = <File>event.target.files[0];
this.fileName = this.selectedFile.name;
let ext = this.selectedFile.name.substring(
this.selectedFile.name.lastIndexOf(".") + 1
);
if (ext.toLowerCase() == "xlsx") {
this.fileType = true;
} else {
window.alert(this.alertType);
this.fileType = false;
}
if (this.fileType) {
this.fileOnHold = true;
}
}
uploadFile() {
if (!this.selectedFile) return;
this.uploadFileSubs = this.containersService
.uploadFile(this.id, this.selectedFile)
.subscribe(
(res: any) => {
console.log(res);
},
(error) => {
console.log(error);
}
);
}
And an HTML part
<input
type="file"
name="file"
id="document"
style="display: none"
(change)="onFileSelected($event)"
accept="application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
#fileInput
/>
<button
class="btn-dark small"
style="white-space: nowrap"
(click)="fileInput.click()"
>
Choose file
</button>
I solved the problem.
I changed the angular's uploadFile service. I removed the third parameter (file's name) when appending file to formData:
uploadFile(
containerId: string,
file: File
): Observable<any> {
const fileData = new FormData();
let fileName = file.name.split(".")[0];
fileData.append("file", file);
const url: string = this.apiUrl + "uploadFile/" + containerId;
if (!this.token) {
const authString = `Bearer ${this.token}`;
httpOptionsFile.headers = httpOptionsFile.headers.append(
"Authorization",
authString
);
}
return this.http.patch<any>(url, fileData, httpOptionsFile);
}
And I changed multer specifications for the router. I specified the file's extension directly in the name and removed it when fetching the name of original file (to prevent duplication of extensions):
const path = require("path");
const multer = require("multer");
const storage = multer.diskStorage({
destination: (req: any, file: any, cb: any) => {
cb(null, "utilities/uploaded-excels");
},
filename: (req: any, file: any, cb: any) => {
// dolocis ime fila
let fileName: string = file.originalname
.split(".")[0]
.toLowerCase()
.split(" ")
.join("-");
cb(null, fileName + "-" + Date.now() + path.extname(file.originalname));
},
});

Uploading large video file with nodejs, multer and cloudinary

My code works very well for small videos up to 50MB however when videos weight more than 50MB, it uploads the video but I dont get any cloudinary url hence the video is not loading in my frontend part . I am using nodejs and multer in my backend with cloudinary as storage and react as my frontend.
Any suggestion ?
Cloudinary config
require("dotenv").config();
const cloudinary = require("cloudinary");
cloudinary.config({
cloud_name: process.env.CLOUD_NAME ,
api_key: process.env.API_KEY ,
api_secret: process.env.API_SECRET ,
});
exports.uploads = (file) => {
return new Promise((resolve) => {
cloudinary.uploader.upload(
file,
(result) => {
resolve({ url: result.url, id: result.public_id });
},
{ resource_type: "auto" }
);
});
};
Video controller
const Video = require("../models/videoModel"),
cloud = require("../config/cloudinaryConfig");
module.exports = {
// Create action for a new video
create: (req, res, next) => {
// First check if the file exists in the Database
let test = {
name: req.files[0].originalname,
url: req.files[0].path,
id: "",
};
console.log(req.files[0].originalname);
Video.find({ name: test.name }, (err, cb) => {
if (err) {
res.json({
error: true,
message: `There was a problem uploading the video because: ${err.message}`,
});
} else {
let file = {
name: req.files[0].originalname,
url: req.files[0].path,
id: "",
};
cloud
.uploads(file.url)
.then((result) => {
Video.create({
name: req.files[0].originalname,
url: result.url,
id: result.id,
});
})
.then((result) => {
res.json({
success: true,
data: result,
});
})
.catch((err) => {
res.json({
error: true,
message: err.message,
});
});
}
});
},
};
Multer config
const multer = require("multer"),
path = require("path");
//multer.diskStorage() creates a storage space for storing files.
const imageStorage = multer.diskStorage({
destination: (req, file, cb) => {
if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
cb(null, path.join(__dirname, "../files"));
} else {
cb({ message: "This file is not an image file" }, false);
}
},
filename: function (req, file, cb) {
cb(null, file.originalname);
},
});
const videoStorage = multer.diskStorage({
destination: (req, file, cb) => {
if (file.mimetype === "video/mp4") {
cb(null, path.join(__dirname, "../files"));
} else {
cb({ message: "This file is not in video format." }, false);
}
},
filename: (req, file, cb) => {
cb(null, file.originalname);
},
});
module.exports = {
imageUpload: multer({ storage: imageStorage }),
videoUpload: multer({ storage: videoStorage }),
};
When uploading files to Cloudinary, the maximum size of the request body can be 100MB. Any request that is larger than this would receive the 413 error you are seeing. To upload files larger than 100MB, these need to be sent in chunks.
Since you are using the Cloudinary NodeJS SDK, you can update your code to use the upload_large method for your uploads instead of the regular upload method.
The upload_large method should be used for all files >100MB as it splits the file and uploads it in parts automatically for you. That said, you can also use this uplaod_large method for all files, even if they are small in filesize and those would work as well.
It takes the exact same parameters as the upload method and also optionally accepts a chunk_size (default 20MB).

Upload a profile pic with Reactjs and Nodejs to MongoDb

I am trying to let the user update their profile with their own avatar but for some reason, it doesn't work. I am sending a FormData from the front-end and catch it with nodeJs before storing it to MongoDB. user has 3 options to update: name, about, avatar. Whenever I try to update the name and about it works just fine but when I am uploading an avatar I get a 500 error. Can you guys take a look? FYI I am a begginer.
Here is my code:
FRONT-END
const handleFileInputChange = (e) => {
const file = e.target.files[0];
previewFile(file);
setUser({
...user,
avatar: file,
});
};
const onSubmit = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append('name', user.name);
formData.append('about', user.about);
formData.append('avatar', user.avatar);
editUserProfile(formData); // external axios.patch f.
};
const editUserProfile = async (formData) => {
try {
await axios.patch('api/v1/users/me', formData, {
headers: {
Authorization: `Bearer ${localStorage.getItem('token')}`,
},
});
dispatch({
type: EDIT_USER,
});
} catch (err) {
console.log(err);
}
};
<form onSubmit={onSubmit} encType="multipart/form-data">
<input
// accept="image/*"
accept=".png, .jpg, .jpeg"
type="file"
name="avatar"
// value={fileInputState}
onChange={handleFileInputChange}
style={{ display: 'none' }}
id="icon-button-file"
/>
...
BACK-END
router.patch('api/v1/users/me', protect, upload.single('avatar'), getMe, editUser = async (req, res) => {
try {
const { name, about } = req.body;
const profileFileds = {};
if (name) profileFileds.name = name;
if (about) profileFileds.about = about;
if (req.file) profileFileds.avatar = req.file.filename;
const user = await User.findByIdAndUpdate(req.params.id, profileFileds, {
new: true,
runValidators: true,
});
if (!user) {
return next(
new custom error...
);
}
res.status(200).json({
status: 'success',
data: {
user,
},
});
} catch (err) {
console.log(err) error 400 ...
}
}););
Sorry guys if it's a long code and I really appreciate it, I am struggling 2 days now and can't figure it out
//MULTER CONFIG just in case but it shouldn't be a problem with it
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/images');
},
filename: function (req, file, cb) {
cb(null, uuidv4() + '-' + Date.now() + path.extname(file.originalname));
},
});
const fileFilter = (req, file, cb) => {
const allowedFileTypes = ['image/jpeg', 'image/jpg', 'image/png'];
if (allowedFileTypes.includes(file.mimetype)) {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 2,
},
fileFilter: fileFilter,
});

Unable to upload image/video files from react-native to nodejs

I am using expo-image-picker in react-native to pick image/video files and multer in nodejs as middleware to download files in directory /public/upload. When i am uploading file along with other parameters from react-native, multer is unable to detect a file present in req.body and hence not downloading any file.
Here is my react-native code using axios
pickImage = async () => {
try {
let options = {
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 1,
// base64:true
}
let result = await ImagePicker.launchImageLibraryAsync(options)
if (!result.cancelled) {
this.setState({ content: result })
}
} catch (E) {
console.log("error in picking image:", E)
}
}
createFormData = (response) => {
const photo = {
uri: response.uri,
type: response.type,
name: "my-img.jpg",
};
const form = new FormData();
form.append('acivityFile',photo);
return form;
};
handleSubmit = async () => {
if (this.state.content) {
const formData = this.createFormData(this.state.content)
console.log("form data:", formData)
try {
const res = await axios.post('http://393ad751391b.ngrok.io/activities',
{
title: "This is the title",
description: "This is a description",
eventType: "LOST & FOUND",
file: formData
},
{
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data'
},
},
)
console.log("res:", res.data);
} catch (err) {
console.log("err in post axios:",err)
}
}
}
Here is my route file handling http requests in server-side
const express = require('express');
const Upload = require('./../utils/multerSetup');
const activityController = require('../Controllers/activityController');
const router = express.Router();
router
.route('/')
.get(activityController.getAllActivities)
.post(
Upload.single('activityFile'),
activityController.addActivity
);
Here is my multerSetup.js file in server-side
const multer = require('multer');
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'public/uploads/');
},
filename: function (req, file, cb) {
const ext = file.mimetype.split('/')[1];
cb(null, file.fieldname + '-' + Date.now() + '.' + ext);
},
});
const upload = multer({ storage });
module.exports = upload;
Here is my activityController.js file in server-side
const Activity = require('./../modals/activityModel');
const User = require('./../modals/user');
exports.getActivity = async (req, res, next) => {
console.log('here');
const activity = await Activity.findById(req.params.id);
res.status(200).json({
status: 'success',
data: {
activity,
},
});
};
exports.addActivity = async (req, res, next) => {
if (req.file) {
let file = {
Ftype: req.file.mimetype.split('/')[0],
name: req.file.filename,
};
req.body.file = file;
}
if (!req.body.location) {
req.body.location = {
coordinates: ['77.206612', '28.524578'],
};
}
if (req.body.votes) {
req.body.votes.diff = req.body.votes.up - req.body.votes.down;
}
req.body.creator = "12345" || "req.userId";
const activity = await Activity.create(req.body);
res.status(201).json({
status: 'success',
data: {
activity,
},
});
};
Also when Content-type:'multipart/form-data, then server console throws Error: Multipart:Boundary not found. When i use Content-type:'application/json', then multer does not work.
I just want to know what is the correct way of uploading files with additional parameters from react-native to nodejs multer. Any suggestions would be a great help!

upload files from different fields in a form using multer

I have a document that contains two fields are of input type="file" and I want to upload both of these on submit.
This post method giving me internal server error 500 on uploading two files but when I upload one file, it is OK.
router.post('/', mediaFiles.uploadSingle('icon_url'), mediaFiles.uploadSingle('background_url'),
async (req, res) => {
name: req.body.name,
icon_url: req.file.path.replace(/\\/g, "/"), // req.file['icon_url']
background_url: req.file.path.replace(/\\/g, "/") // req.file['background_url']
})
you can ignore this MediaFiles class because it provides traditional code to upload images with multer
import multer from "multer";
import path from "path";
class MediaFiles {
private storage = multer.diskStorage({
destination: 'uploads/',
filename: function (req, file, callback) {
callback(
null,
file.originalname.replace(/\.[^/.]+$/, "") + '-' + Date.now() + path.extname(file.originalname))
}
})
uploadSingle(fieldName?: string) {
try {
return multer({
storage: this.storage,
limits: { fileSize: 1024 * 1024 * 1 }, // 1MB = 1024 * 1024 * 1
fileFilter: function (req, file, callback) {
const fileTypes = /jpeg|jpg|png/;
const extName = fileTypes.test(path.extname(file.originalname).toLowerCase());
const mimeType = fileTypes.test(file.mimetype);
if (extName && mimeType) {
callback(null, true)
} else {
callback(new Error('Error: Images Only!'), null)
}
}
}).single(fieldName);
} catch (err) {
console.log(err.message)
}
}
}
export default new MediaFiles();
I don't think you could have two multer objects, I was having the same problem and here is what worked for me.
const storage = multer.diskStorage()
const mediaFiles = multer({
storage:storage })
.fields([{ name: 'icon_url', maxCount: 1 }, { name: 'background_url', maxCount: 1 } ]
router.post('/', mediaFiles, async (req, res) => {
console.log(req.files) // req.files is an array of files
}

Resources