post input type file to server node.js from angular service call - node.js

I have simple multipart formdata
<form action="/upload" enctype="multipart/form-data" method="post">
<span class="btn btn-file">
<input type="file" name="file" ng-model="file"/>
<span class="btn btn-primary" ng-click="upload()">Upload</span>
</span>
</form>
What I want to do it, post all the information related to file to the server written in node.js
server.js This is file upload handler written in node. Formidable expects all parameters of a file.
upload: function uploadfn (req, res) {
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
// `file` is the name of the <input> field of type `file`
var old_path = files.file.path,
file_size = files.file.size,
file_ext = files.file.name.split('.').pop(),
index = old_path.lastIndexOf('/') + 1,
file_name = old_path.substr(index),
new_path = path.join(process.env.PWD, '/uploads/', file_name + '.' + file_ext);
fs.readFile(old_path, function(err, data) {
fs.writeFile(new_path, data, function(err) {
fs.unlink(old_path, function(err) {
if (err) {
res.status(500);
res.json({'success': false});
} else {
res.status(200);
res.json({'success': true});
}
});
});
});
});
}
The things I'm stuck at is, I have service call ready in angular as follows:
service.factory('FileUpload', function ($resource) {
return $resource('/upload', {}, {
post: {method: 'POST'}
});
});
This call hits the backend from angular controller as follows
$scope.upload = function(){
console.log($scope.file);
FileUpload.post(function(){
});
}
I'm not sure how to post the file submit so that node can catch it. Also $scope.file is undefined.
Please help me solve this.

There's a good directive for file upload for angularjs, try to use it
https://github.com/danialfarid/angular-file-upload

Related

File upload (with other inputs and textarea) using Angular 13 and Node Js

I am trying to upload files to server using Angular and Node, using multer.
I have Todo Model as :
export class TodoModel {
todo_id !:number;
todo_title !:string;
todo_description !:string;
todo_status !:number;
todo_deleted_flag !:boolean;
todo_image !:Object;
}
todo.component.ts
title:string;
desc:string;
selected_image:File = null;
fileUploadListener(event){
//console.log(event)
//console.log(event.target.files[0])
this.selected_image = <File>event.target.files[0]
console.log(this.selected_image)
}
onSubmit(form:NgForm){
const fd = new FormData()
if(this.selected_image) {
fd.append('todo_image',this.selected_image,this.selected_image.name)
}
console.log(fd);
const todo_model : TodoModel = {
todo_id: null,
todo_title:this.title,
todo_description:this.desc,
todo_status:1,
todo_deleted_flag:false,
todo_image:null
}
console.log(fd);
this.todoAdd.emit(todoadded);
this.todoAdd_DB.emit(todo_model);
this.addTodo_DB(todo_model, fd)
form.resetForm();
}
addTodo_DB(todo_db: TodoModel, fileUpload:Object){
//const todo_db
return this.http.post<{message:any}>('http://localhost:3000/api/todos/post_all_todos_db', todo_db,fileUpload).subscribe(data => {
console.log(data.message);
console.log(todo_db);
})
}
todo.component.html
<div class="col-md-12">
<form (ngSubmit)="onSubmit(todoForm)" #todoForm="ngForm">
<div class="mb-3">
<label for="todo_title" class="form-label">Title</label>
<input type="text" class="form-control" id="todo_title" [(ngModel)]="title" name="title">
</div>
<div class="mb-3">
<label for="label" class="form-label">Description</label>
<textarea class="form-control" id="todo_description" [(ngModel)]="desc" name="desc"></textarea>
</div>
<div class="mb-3">
<label for="todo_image" class="form-label">Image</label>
<input type="file" class="form-control" id='todo_image' (change)="fileUploadListener($event)">
</div>
<button type="submit" class="btn btn-success">Add To Do</button>
</form>
</div>
</div>
And on Server Side, using Node Js and PgSQL :-
app.post('/api/todos/post_all_todos_db',upload_using_multer.single('todo_images') , (req, res, next) => {
// const todo_post = req.body;
const files = req.file;
console.log(files) // - ----------> This does NOT work
console.log(req.body) //------> this works
//PGSQL insert query here
res.status(201).json({
message:"Post Added Successfully"
})
})
While doing console.log() in Angular side, I am getting the form data, but, on Node Js side, I get it as null.
Almost every tutorial I see, uses only one file upload , and that too, try to submit the form using the Form's action. I dont want to do that, so I tried doing this.
I
i once had the same issue and solved it with formdata, my example uploads multiple files. here is an example:
Node.JS
const serverRoutes = (function () {
const express = require('express');
const router = express.Router();
const multer = require('multer');
const upload = multer();
router.post('/myresource', upload.any(), (req, res) => {
console.log(req.files);
});
return router;
});
on angular
export class DataService {
constructor(private http: HttpClient) { }
sendMyFiles(file): Observable<MyResponse> {
const formData = new FormData();
formData.append("file", file);
return this.http.post<MyResponse>(
`${environment.backendAPI}myresource`,
formData
);
}
}

React reloads the page after replacing images

I am uploading images to a server. If it is present and replaced, then React refreshes the page with a loss of state. How can I stop this behavior?
Node:
let form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
let {size, path, name, type} = files.image,
newpath = pathLib.join(__dirname, '../client/public/uploads') + name;
fs.rename(path, newpath, function (err) {
if(err) throw err;
});
});
React:
<form id="uploadForm">
<input id="uploadInput" name="image" type="file" />
</form>
<span onClick={() => {
let form = document.querySelector("#uploadForm"),
formData = new FormData(form);
if(form.querySelector("#uploadInput").files.length)
uploadFiles(formData, (res) => {
console.log(res.data.errors);
});
}}>Save</span>
An important addition! Page refreshed even without interaction with React components. Replacing an image through the Windows file manager calls the re-render.
Just call event.preventDefault() when submit form. See the example here:
<form id="formSubmit"}>
<input id="uploadInput" name="image" type="file" />
<button type="submit"></button>
</form>
document.getElementById('formSubmit').addEventListener('submit',function(event){
event.preventDefault()
// write here your others code
})

How to convert blob object in EJS Template

I am working on patient photo upload using express, mongodb, multer, ejs, and croppiejs. When user uploads a photo they have an option to crop it. I am saving the cropped photo in a collection as BLOB object in a field called croppedPhoto.
Now, i want to display that cropped photo on front-end. I am passing the patients object (which contains all the data fields of a record including cropped photo).
I am thinking of converting that blob object to base64 and display it. But the issue is I am not sure how to use croppedPhoto field value in ejs template to convert it.
server.js [Finding all patients and passing in to ejs template - includes croppedPhoto field as well]
app.get('/', async (req, res) => {
const patients = await Patient.find();
res.render('index', { patients: patients });
});
index.ejs [want to display the photo in img tag]
<div class="flex flex-wrap mt-10">
<% patients.forEach(patient => { %>
<div
class="flex flex-col items-center justify-center h-auto lg:h-auto lg:w-32 flex-none bg-cover rounded-t lg:rounded-t-none lg:rounded-l text-center overflow-hidden">
<img src="<%= patient.croppedPhoto %>" class="my-3 w-20 h-20 rounded-full" alt="Patient Photo">
</div>
<% }) %>
</div>
Thanks!!
Usually and when it comes to uploading files to the server, you have to avoid saving the file itself in the database, instead, you can move the file from the client's desktop to the directory you want (your application images folder where you store the images) using Express file upload , and you save the path of that file in the database, normally it would be something like this : /images/test.png .
Here is an example :
router.route('/add').post(function (req, res) {
if (req.files && req.body.name) {
var file = req.files.file
// to move the file to the direct i want !
file.mv("client/public/img/client/categories/" + file.name, err => {
if (err) {
console.error(err);
return res.status(500).send(err);
}
});
var newCategorie = new Categorie({
name: req.body.name,
imgUrl: "/img/client/categories/" + file.name // TO SAVE THE PATH
});
}
newCategorie
.save()
.then(categories => res.json(categories))
.catch(err => res.status(400).json('Error: ' + err));
} else {
res.status(400).json({ msg: "Please enter all fields" });
}
});
Then in your EJS template, it would be very easy to access the src of the image : <img src="OBJECT.ImgURL" />

Save file to mongodb using angular and Nodejs

I am trying to upload an image to mongodb using angular and nodejs. The code is below. I got the backend working but the problem is with the html input i get 'C:fakepath/file.xyz'. I was looking online and saw that there is not a way to get the relative path of the file. Can someone please tell me how i can change my front end code to get and send the file path to the backend to then save. I read that the browser doesnt allow relative path of the file but then how can I upload. Thanks!
The nodejs image save method is:
async function SaveImage(userParam) {
const entry = new imageEntries(userParam);
entry.image.data = fs.readFileSync(userParam.imagePath);
entry.image.contentType = 'image/png';
await entry.save();
}
The html code is:
<div class="upload-btn-wrapper">
<button class="btn">Upload a file</button>
<input type="file" name="myfile" id="myFile" />
</div>
What I pass as the path in the backend is:
ImageJournal.imagePath = (<HTMLInputElement>document.getElementById('myFile')).value;
but with the code above i get the following error:
ENOENT: no such file or directory, open 'C:\fakepath\chapter9problemsandanswers.doc'
Ok here it is:
HTML:
<div class="form-group">
<label for="pdf">PDF</label>
<input type="file" id="pdf" (change)="onFileChange($event)" #fileInput>
<button type="button" class="btn btn-sm btn-default" (click)="clearFile()">clear file</button>
</div>
TS:
import { Component, OnInit, ElementRef, ViewChild } from '#angular/core';
#ViewChild('fileInput') fileInput: ElementRef;
public image;
onFileChange(event) {
let reader = new FileReader();
if(event.target.files && event.target.files.length > 0) {
let file = event.target.files[0];
reader.readAsDataURL(file);
let value = <String>reader.result;
reader.onload = () => {
this.image = {
filename: file.name,
filetype: file.type,
value: value.split(',')[1]
};
};
}
}
Then send the image with http post with a service.
On the server:
// send file
app.post('/api/sendFile', function (req, res) {
File.create({
filename: req.body.filename,
filetype: req.body.filetype,
value: req.body.value
}, function (err, file) {
if (err)
res.send(err);
else {
const response = {
name: file.filename
}
res.send(response);
}
});
});
This is written with mongoDb and mongoose and I have a model named File.
This is all it need to save it.

sails.js view does not load

I made a controller which get data from a rest api and
serializes them to .xls file.
In my web view I have a button with "Create xls data" which call my controller.
Then my controller sierialises and reload this view with the xls download link and a "Download data" button.
My view import_export_data_page.ejs:
At start button "Create xls data" is displayed.
<%
if(typeof link == 'undefined'){
%>
<button type="button" class="btn btn-primary" id="button_get_xls_file">Create xls data</button>
<%
}else {
%>
<button type="button" class="btn btn-primary"></button>
<%
}
%>
<script type="text/javascript">
$('#button_get_xls_file').click(function(){
var projectName = getCurrentServiceName(currentService);
$.get( "/api/export_xls_data", { url : currentService, projectname : projectName} ).done(function( data ) {
});
});
</script>
In my controller :
exportXLS : function(req,res)
{
var request = require('request');
var categories;
//get informations
request(url + "/places", function (error, response, body) {
categories = JSON.parse(body);
/*
* Parsing tacks 3 seconds max
*/
//if file exists delete and create file
fs.exists(fileName, function (exists) {
if(exists){
fs.unlinkSync(fileName);
}
fs.writeFile(fileName, xls, 'binary',function(err){
if(err){
console.log(err);
res.status(500);
return res.send("");
}else{
var downloadLink = req.headers.host+'/xls/'+currentProject.split(' ').join('')+'_data.xls';
console.log(downloadLink);
return res.view('import_export_data_page',{link : downloadLink});
});
});
}
}
My file is created. My link works but my view is not reloaded.
Your view is not reloaded because your making an AJAX call. There is nothing in your code to tell the page to reload the view.
I think you want to change this:
$.get( "/api/export_xls_data", { url : currentService, projectname : projectName} ).done(function( data ) {});
to:
window.location.href = '/api/export_xls_data?url=' + currentService + '&projectname=' + projectName

Resources