How to send data along with file in http POST (angularjs + expressjs)? - angularjs

Situation
I implemented file uploading. Front-end code is taken from popular tutorial. I send POST in service:
myApp.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file, uploadUrl){
var fd = new FormData();
fd.append('file', file);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
}]);
Typical multer usage in back-end:
exports.postFile = function (req, res) {
var storage = multer.diskStorage({ //multers disk storage settings
destination: function (req, file, cb) {
cb(null, '../documents/')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
});
var upload = multer({ //multer settings
storage: storage
}).single('file');
upload(req, res, function (err) {
if (err) {
res.json({error_code: 1, err_desc: err});
return;
}
res.json({error_code: 0, err_desc: null});
})
};
That works.
Question
How to send some data in the same POST, let say string "additional info"?
What I tried
I tried to add data in service, i.e.:
...
var fd = new FormData();
fd.append('file', file);
fd.append('model', 'additional info');
$http.post(uploadUrl, fd, {...})
It seems to be sent, but I don't know how to receive it in back-end. Tried to find it in req (without success).

To send data (i.e. json) and file in one POST request add both to form data:
myApp.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file, uploadUrl){
var fd = new FormData();
fd.append('file', file);
var info = {
"text":"additional info"
};
fd.append('data', angular.toJson(info));
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
}]);
On server side it's in req.body.data, so it can be received i.e. like this:
upload(req, res, function (err) {
if (err) {
res.json({error_code: 1, err_desc: err});
return;
}
console.log(req.body.data);
res.json({error_code: 0, err_desc: null});
})

You can get the file from req.files and save it with fs.writeFile.
fs.readFile(req.files.formInput.path, function (err, data) {
fs.writeFile(newPath, data, function (err) {
if (err) {
throw err;
}
console.log("File Uploaded");
});
});

You can do something like this:
$http({
url: url,
method: 'POST',
data: json_data,
headers: {'Content-Type': 'application/json'}
}).then(function(response) {
var res = response.data;
console.log(res);
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Or just add the data property to your function.
var userObject = {
email: $scope.user.email,
password: $scope.user.password,
fullName: $scope.user.fullName
};
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
data: userObject,
headers: {'Content-Type': 'application/json'}
})
You can try something like this on the backend.
req.on('data', function (chunk) {
console.log(chunk);
});

Related

How to POST binary files with AngularJS (with upload DEMO)

unable to send file with angular post call
I am trying to post .mp4 file with some data through ionic 1 with angular 1. While posting through POSTMAN it is fine and working. I am getting Success = false in my application.
in POSTMAN, no headers and data is bellow,
Service url with POST request http://services.example.com/upload.php
body in form data
j_id = 4124, type = text
q_id = 6, type = text
u_id = 159931, type = text
file = demo.mp4, type = file
in my app:
$rootScope.uploadQuestion = function () {
var form = new FormData();
form.append("j_id", "4124");
form.append("q_id", "6");
form.append("u_id", "159931");
form.append("file", $rootScope.videoAns.name); //this returns media object which contain all details of recorded video
return $http({
method: 'POST',
headers: { 'Content-Type': 'multipart/form-data' }, // also tried with application/x-www-form-urlencoded
url: 'http://services.example.com/upload.php',
// url: 'http://services.example.com/upload.php?j_id=4124&q_id=8&u_id=159931&file='+$rootScope.videoAns.fullPath,
// data: "j_id=" + encodeURIComponent(4124) + "&q_id=" + encodeURIComponent(8) + "&u_id=" + encodeURIComponent(159931) +"&file=" + encodeURIComponent($rootScope.videoAns),
data: form,
cache: false,
timeout: 300000
}).success(function (data, status, headers, config) {
if (status == '200') {
if (data.success == "true") {
alert('uploading...');
}
}
}).error(function (data, status, headers, config) {
});
}
RECOMMENDED: POST Binary Files Directly
Posting binary files with multi-part/form-data is inefficient as the base64 encoding adds an extra 33% overhead. If the server API accepts POSTs with binary data, post the file directly:
function upload(url, file) {
if (file.constructor.name != "File") {
throw new Error("Not a file");
}
var config = {
headers: {'Content-Type': undefined},
transformRequest: []
};
return $http.post(url, file, config)
.then(function (response) {
console.log("success!");
return response;
}).catch(function (errorResponse) {
console.error("error!");
throw errorResponse;
});
}
Normally the $http service encodes JavaScript objects as JSON strings. Use transformRequest: [] to override the default transformation.
DEMO of Direct POST
angular.module("app",[])
.directive("selectNgFiles", function() {
return {
require: "ngModel",
link: postLink
};
function postLink(scope, elem, attrs, ngModel) {
elem.on("change", function(event) {
ngModel.$setViewValue(elem[0].files);
});
}
})
.controller("ctrl", function($scope, $http) {
var url = "//httpbin.org/post";
var config = {
headers: { 'Content-type': undefined }
};
$scope.upload = function(files) {
var promise = $http.post(url,files[0],config);
promise.then(function(response){
$scope.result="Success "+response.status;
}).catch(function(errorResponse) {
$scope.result="Error "+errorRespone.status;
});
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app" ng-controller="ctrl">
<input type="file" select-ng-files ng-model="files">
<br>
<button ng-disabled="!files" ng-click="upload(files)">
Upload file
</button>
<pre>
Name={{files[0].name}}
Type={{files[0].type}}
RESULT={{result}}
</pre>
</body>
Posting with 'Content-Type': 'multipart/form-data'
When posting data using the FormData API, it is important to set the content type to undefined:
function uploadQuestion(file) {
var form = new FormData();
form.append("j_id", "4124");
form.append("q_id", "6");
form.append("u_id", "159931");
form.append("file", file); //this returns media object which contain all details of recorded video
return $http({
method: 'POST',
headers: { 'Content-Type': undefined ̶'̶m̶u̶l̶t̶i̶p̶a̶r̶t̶/̶f̶o̶r̶m̶-̶d̶a̶t̶a̶'̶ }, // also tried with application/x-www-form-urlencoded
url: 'http://services.example.com/upload.php',
data: form,
̶c̶a̶c̶h̶e̶:̶ ̶f̶a̶l̶s̶e̶,̶
timeout: 300000
̶}̶)̶.̶s̶u̶c̶c̶e̶s̶s̶(̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶d̶a̶t̶a̶,̶ ̶s̶t̶a̶t̶u̶s̶,̶ ̶h̶e̶a̶d̶e̶r̶s̶,̶ ̶c̶o̶n̶f̶i̶g̶)̶ ̶{̶
}).then(function(response) {
var data = response.data;
var status = response.status;
if (status == '200') {
console.log("Success");
}
̶}̶)̶.̶e̶r̶r̶o̶r̶(̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶d̶a̶t̶a̶,̶ ̶s̶t̶a̶t̶u̶s̶,̶ ̶h̶e̶a̶d̶e̶r̶s̶,̶ ̶c̶o̶n̶f̶i̶g̶)̶ ̶{̶
}).catch(function(response) {
console.log("ERROR");
//IMPORTANT
throw response;
});
}
When the XHR API send method sends a FormData Object, it automatically sets the content type header with the appropriate boundary. When the $http service overrides the content type, the server will get a content type header without the proper boundary.

Redirecting after upload

I'm trying to redirect after a file upload but when I try to redirect on AngularJS side, it is not working.
Node.js :
app.post('/upload', upload.single('propt'), function (req, res) {
res.writeHead(200, {"Content-Type": "text/html; charset=utf-8"});
res.send();
});
AngularJS :
$scope.uploadFile = function () {
var fichier = $scope.monFichier;
var uploadUrl = "/upload";
console.dir(fichier);
var fd = new FormData();
fd.append('file', fichier);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: { 'Content-Type': "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }
})
.then(function () {
$window.location.href = '/users.html';
});
}
UPDATE : The "then" part is not executed (I tried with a simple console.log() to test it)
you redirect the page by using this code
$window.location.href = '/users.html';
window.location.href = '/users.html';
Try $location
You would need to inject $location in the controller and $location.path('/user') would redirect to http://example.com/#/user
.then(function () {
$location.path('/user');
});

how to send extra data in request?

I want to send itemId in http request. how to do it and what will I see on server req?
here is request:
var fd = new FormData();
var itemId = scope.vm.item._id;
fd.append('file', scope.files[0]);
$http.post('http://localhost:8090/file-upload', fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
});
server
app.post('/file-upload', function(req, res, next) {
console.log("received file");
var pathFile = ' ';
var wId = "itemId";
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, './uploads/attachments');
pathFile = file.originalname;
},
filename: function (req, file,itemId, cb) {
cb(null, file.originalname);
console.log(itemId);
}
});
var upload = multer({ storage : storage }).single('file');
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
//save file path in work items doc.attachments
var path = './uploads/attachments/'+pathFile;
res.end("File is uploaded");
});
serve code added. How to get itemId on server side?
Theres a couple a ways you could do it, you could just set the params property in your post options and pass in an object with id as a property.
var fd = new FormData();
var itemId = scope.vm.item._id;
fd.append('file', scope.files[0]);
$http.post('http://localhost:8090/file-upload', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined},
params: {id: itemId}
});
You can append JSON string to the FromData object like below.
fd.append('params', JSON.stringify({itemId: itemId}));
On the server side, you will get JSON string in params key.
simple add your parameters in params and pass your all the parameters.
$http.post('http://localhost:8090/file-upload', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined},
params: {id: scope.vm.item._id}
});
hope this works for you.

Upload file using Angular $resource

I am trying to upload a file using angular $resource, i am able to hit the Api but the request doesn't have any file. I have tried the solution here as well: AngularJS: Upload files using $resource (solution)
My Controller:
var formData = new FormData();
formData.append('file', $scope.file);
appService.manualDataUpload(formData)
.then(function (response) {
//do something here
})
.catch(function (error) {
logger.error('An error occurred while uploading the file !', error);
});
My Factory service:
function manualDataUpload(formData) {
var /** #type {angular.Resource} */
manualDataUploadResource = $resource(serviceBase + '/ManualDataUpload', formData,
{
save: {
method: 'POST',
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
}
});
return manualDataUploadResource
.save()
.$promise;
}
Removing the formData from $resource and adding in the body worked.
function manualDataUpload(formData) {
var /** #type {angular.Resource} */
manualDataUploadResource = $resource(serviceBase + '/ManualDataUpload', {},
{
save: {
method: 'POST',
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
}
});
return manualDataUploadResource
.save(formData)
.$promise;
}

AngularJS Error while Uploading A File

This code:
App.service('fileUpload', ['$http', function($http) {
this.uploadFileToUrl = function(file, uploadUrl) {
console.log("inside upload file service js ");
var fd = new FormData();
fd.append('file', file);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
})
.success(function(response) {
console.log("file uploaded sucessfully " + response);
})
.error(function(error) {
console.log("Error while uploading file " + JSON.stringify(error));
});
}
}]);
Produces this error: "container has no method handling POST"
{"error":{"name":"Error","status":404,"message":"Shared class \"container\" has no method handling POST /5555-1111","statusCode":404,"stack":"Error:

Resources