Angular suggests setting 'Content-Type' header to undefined (https://docs.angularjs.org/api/ng/service/$http) so that the browser can pick up the file data and supply the correct Content-Type header.
But even when I upload a PDF, the content-type is set to 'text/plain;charset=UTF-8'. I want the content-type to be set to multipart, because this is what the backend expects, but how can I make this happen, if the browser is responsible for setting the content-type?
I have also tried this post's tactic but to no avail. I have also tried using Dropzone.js with the same result.
Here's the code for the request itself:
uploadFile: function(token, baseurl, projectname, filename, file) {
var dataUpload= {
method: 'PUT',
url: baseurl + '/projects/' + projectname + '/files/' + filename,
transformRequest: angular.identity,
headers: {
'Authorization': 'bearer ' + token,
'Accept': "application/json",
'Content-Type': undefined
},
data: {
'files': file
}
};
return dataUpload;
}
Below I am including the code from the post previously linked which is supposed to work but when I used it with my own url the same thing happens: the browser sets Content-Type to 'text/plain;charset=UTF-8' and I get a 415 error from the backend. How? Why? Any help (including workarounds for the backend) would be extremely appreciated. I've been working on this for days.
The JavaScript:
var myApp = angular.module('myApp', []);
myApp.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
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(){
});
}
}]);
myApp.controller('myCtrl', ['$scope', 'fileUpload', function($scope, fileUpload){
$scope.uploadFile = function(){
var file = $scope.myFile;
console.log('file is ' );
console.dir(file);
var uploadUrl = "/fileUpload";
fileUpload.uploadFileToUrl(file, uploadUrl);
};
}]);
The HTML:
<div ng-controller = "myCtrl">
<input type="file" file-model="myFile"/>
<button ng-click="uploadFile()">upload me</button>
</div>
I guess it's too late to answer this but in case someone came across with the same problem.
The error in your code is here:
data: {
'files': file
}
Your form data object already has the information of the field your backend is expecting so, you need to change that line for:
data: file
If you've created the FormData object manually you'll probably have something like this:
var fd = new FormData();
fd.append("files", $scope.file);
Related
This question already has an answer here:
How to POST binary files with AngularJS (with upload DEMO)
(1 answer)
Closed 3 years ago.
I have some problem on FormData of Angular.js
My code is this:
angular
.module("appFoco", [])
.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}])
.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file) {
var fd = new FormData();
fd.append('file', file);
$http.post('/send/sendPlanilha', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function() {
})
.error(function() {
});
}
}])
.controller("LoginFormPDF",['$scope','fileUpload', function($scope,fileUpload){
$scope.sendPlanilha = function(){
console.log($scope.email, $scope.nome);
var file = $scope.myFile;
console.dir(file);
$scope.usuario = {"usuarioEmail" : $scope.email, "usuarioNome" : $scope.nome}
fileUpload.uploadFileToUrl(file);
}
}]);
When I do the $http.post, the fd on fd.append is empty, and I do not know why this is happend. On fd will have a file like arq.xls .
I already saw many kins of tutorials and I did not find a solution.
The backend code is in NodeJs, so I need to take a file on fd.append and send to $http.post for a another function on Nodejs, this function is below:
app.post('/send/sendPlanilha', function(req, res, next){}
So, my question is, Why fd on fd.append is empty? And how I can fix this?
It is more efficient to send the file directly:
app.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file) {
̶v̶a̶r̶ ̶f̶d̶ ̶=̶ ̶n̶e̶w̶ ̶F̶o̶r̶m̶D̶a̶t̶a̶(̶)̶;̶
̶f̶d̶.̶a̶p̶p̶e̶n̶d̶(̶'̶f̶i̶l̶e̶'̶,̶ ̶f̶i̶l̶e̶)̶;̶
̶$̶h̶t̶t̶p̶.̶p̶o̶s̶t̶(̶'̶/̶s̶e̶n̶d̶/̶s̶e̶n̶d̶P̶l̶a̶n̶i̶l̶h̶a̶'̶,̶ ̶f̶d̶,̶ ̶{̶
return $http.post('/send/sendPlanilha', file, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
}
}])
The base64 encoding of Content-Type: multipart/form-data adds an extra 33% overhead. And the backend then needs to decode the base64 data.
I have a form with two input text and one upload. I have to send it to the server but I have some problem concatenating the file with the text. The server expects this answer:
"title=first_input" "text=second_input" "file=my_file.pdf"
This is the html:
<input type="text" ng-model="title">
<input type="text" ng-model="text">
<input type="file" file-model="myFile"/>
<button ng-click="send()">
This is the Controller:
$scope.title = null;
$scope.text = null;
$scope.send = function(){
var file = $scope.myFile;
var uploadUrl = 'my_url';
blockUI.start();
Add.uploadFileToUrl(file, $scope.newPost.title, $scope.newPost.text, uploadUrl);
};
This is the Directive fileModel:
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
And this is the Service which call the server:
this.uploadFileToUrl = function(file, title, text, uploadUrl){
var fd = new FormData();
fd.append('file', file);
var obj = {
title: title,
text: text,
file: fd
};
var newObj = JSON.stringify(obj);
$http.post(uploadUrl, newObj, {
transformRequest: angular.identity,
headers: {'Content-Type': 'multipart/form-data'}
})
.success(function(){
blockUI.stop();
})
.error(function(error){
toaster.pop('error', 'Errore', error);
});
}
If I try to send, I get Error 400, and the response is: Multipart form parse error - Invalid boundary in multipart: None.
The Payload of Request is: {"title":"sadf","text":"sdfsadf","file":{}}
Don't serialize FormData with POSTing to server. Do this:
this.uploadFileToUrl = function(file, title, text, uploadUrl){
var payload = new FormData();
payload.append("title", title);
payload.append('text', text);
payload.append('file', file);
return $http({
url: uploadUrl,
method: 'POST',
data: payload,
//assign content-type as undefined, the browser
//will assign the correct boundary for us
headers: { 'Content-Type': undefined},
//prevents serializing payload. don't do it.
transformRequest: angular.identity
});
}
Then use it:
MyService.uploadFileToUrl(file, title, text, uploadUrl).then(successCallback).catch(errorCallback);
Here is the complete solution
html code,
create the text anf file upload fields as shown below
<div class="form-group">
<div>
<label for="usr">User Name:</label>
<input type="text" id="usr" ng-model="model.username">
</div>
<div>
<label for="pwd">Password:</label>
<input type="password" id="pwd" ng-model="model.password">
</div><hr>
<div>
<div class="col-lg-6">
<input type="file" file-model="model.somefile"/>
</div>
</div>
<div>
<label for="dob">Dob:</label>
<input type="date" id="dob" ng-model="model.dob">
</div>
<div>
<label for="email">Email:</label>
<input type="email"id="email" ng-model="model.email">
</div>
<button type="submit" ng-click="saveData(model)" >Submit</button>
directive code
create a filemodel directive to parse file
.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};}]);
Service code
append the file and fields to form data and do $http.post as shown below
remember to keep 'Content-Type': undefined
.service('fileUploadService', ['$http', function ($http) {
this.uploadFileToUrl = function(file, username, password, dob, email, uploadUrl){
var myFormData = new FormData();
myFormData.append('file', file);
myFormData.append('username', username);
myFormData.append('password', password);
myFormData.append('dob', dob);
myFormData.append('email', email);
$http.post(uploadUrl, myFormData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
}]);
In controller
Now in controller call the service by sending required data to be appended in parameters,
$scope.saveData = function(model){
var file = model.myFile;
var uploadUrl = "/api/createUsers";
fileUpload.uploadFileToUrl(file, model.username, model.password, model.dob, model.email, uploadUrl);
};
You're sending JSON-formatted data to a server which isn't expecting that format. You already provided the format that the server needs, so you'll need to format it yourself which is pretty simple.
var data = '"title='+title+'" "text='+text+'" "file='+file+'"';
$http.post(uploadUrl, data)
This never gonna work, you can't stringify your FormData object.
You should do this:
this.uploadFileToUrl = function(file, title, text, uploadUrl){
var fd = new FormData();
fd.append('title', title);
fd.append('text', text);
fd.append('file', file);
$http.post(uploadUrl, obj, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
blockUI.stop();
})
.error(function(error){
toaster.pop('error', 'Errore', error);
});
}
Using $resource in AngularJS you can do:
task.service.js
$ngTask.factory("$taskService", [
"$resource",
function ($resource) {
var taskModelUrl = 'api/task/';
return {
rest: {
taskUpload: $resource(taskModelUrl, {
id: '#id'
}, {
save: {
method: "POST",
isArray: false,
headers: {"Content-Type": undefined},
transformRequest: angular.identity
}
})
}
};
}
]);
And then use it in a module:
task.module.js
$ngModelTask.controller("taskController", [
"$scope",
"$taskService",
function (
$scope,
$taskService,
) {
$scope.saveTask = function (name, file) {
var newTask,
payload = new FormData();
payload.append("name", name);
payload.append("file", file);
newTask = $taskService.rest.taskUpload.save(payload);
// check if exists
}
}
Assume that we want to get a list of certain images from a PHP server using the POST method.
You have to provide two parameters in the form for the POST method. Here is how you are going to do.
app.controller('gallery-item', function ($scope, $http) {
var url = 'service.php';
var data = new FormData();
data.append("function", 'getImageList');
data.append('dir', 'all');
$http.post(url, data, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).then(function (response) {
// This function handles success
console.log('angular:', response);
}, function (response) {
// this function handles error
});
});
I have tested it on my system and it works.
I am going with file upload issue, in which I am using angular in front-end and Java at backend and uploading image on S3 bucket. I think there is no issue in java code because when I am using this upload URL on postman it is going well, I am Attaching Postman screenshot to showcase how it is working fine
Here is My AngularJS Controller as follows :
contactUs.controller('contactController', ['$scope','$http',
function($scope,$http) { $scope.uploadFile = function(){
var file = $scope.myFile;
console.log('file is ' );
console.dir(file);
var uploadUrl = "uploadURL";
var fd = new FormData(file);
fd.append('files', file);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': 'multipart/form-data',
'Authorization': 'Basic QHN0cmlrZXIwNzoxMjM0NTY='}
})
.success(function(response){
console.log(response);
})
.error(function(error){
console.log(error);
});
};
}]);
Here is My AngularJS Directive as follows :
contactUs.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
console.log(model);
console.log(modelSetter);
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
The HTML is as follows :
<input type = "file" name="files" file-model = "myFile"/>
<button ng-click = "uploadFile()">upload me</button>
The Java controller is as follows :
#Path("/upload")
#POST
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces("application/text")
public Response uploadFile(#FormDataParam("files") List<FormDataBodyPart> bodyParts,#FormDataParam("files") FormDataContentDisposition fileDispositions) {
/* Save multiple files */
BodyPartEntity bodyPartEntity = null;
String fileName = null;
for (int i = 0; i < bodyParts.size(); i++) {
bodyPartEntity = (BodyPartEntity) bodyParts.get(i).getEntity();
fileName = bodyParts.get(i).getContentDisposition().getFileName();
s3Wrapper.upload(bodyPartEntity.getInputStream(), fileName);
}
String message= "File successfully uploaded !!";
return Response.ok(message).build();
}
The Error I am getting with the AngularJS is below :
400 - Bad Request
1) To POST File data, You don't need to provide content-type as Multi part/form-data. Because It understand data type automatically. So just pass headers: {'Content-Type': undefined}.
2) As you show in your postman, key is files then If you are providing name="files" and fd.append("files",file), It will not process as files key is on both side. So, Remove name="files" from HTML and process the upload file then.
Usually I use following with $http to send multi-part form data. Please try this.
var formdata = new FormData();
formdata.append('files', file);
return $http.post(uploadUrl, formdata, { transformRequest: angular.identity, headers: {'Content-Type': undefined} });
I am tryout on save in local project folder using angular and i have not correct code anyone put it your solution help me lot more and then my code here as
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(){
});
}
This is an example code to upload files. You can try it out using this example.
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
</head>
<body ng-app = "myApp">
<div ng-controller = "myCtrl">
<input type = "file" file-model = "myFile"/>
<button ng-click = "uploadFile()">upload me</button>
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
myApp.service('fileUpload', ['$https:', function ($https:) {
this.uploadFileToUrl = function(file, uploadUrl){
var fd = new FormData();
fd.append('file', file);
$https:.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
}]);
myApp.controller('myCtrl', ['$scope', 'fileUpload', function($scope, fileUpload){
$scope.uploadFile = function(){
var file = $scope.myFile;
console.log('file is ' );
console.dir(file);
var uploadUrl = "/fileUpload";
fileUpload.uploadFileToUrl(file, uploadUrl);
};
}]);
</script>
Hey Kalithas KN and welcome to StackOverflow.
For file upload, I have found the following Angular JS library works the best for me
https://github.com/danialfarid/ng-file-upload
The upload method will look something like this
$scope.upload = function (file) {
Upload.upload({
url: 'upload/url',
data: {file: file, 'username': $scope.username}
}).then(function (resp) {
console.log('Success ' + resp.config.data.file.name + 'uploaded. Response: ' + resp.data);
}, function (resp) {
console.log('Error status: ' + resp.status);
}, function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
});
};
In your template, you would do something like this
<div class="button" ngf-select="upload($file)">Upload on file select</div>
Also, the library can handle drag and drop file upload which i think is always a nice addition.
I hope this helps. Please let me know if you need more clarifications.
I have the following HTML.
<form >
<input type="file" file-model="myFile"/>
<button ng-click="uploadFile()">upload me</button>
</form>
And inside controller I have following function
$scope.uploadFile = function() {
var file = $scope.myFile; //when I try console.log(file...it says undefined)
var fd = new FormData();
fd.append('file', file);
$http.post("url", fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined},
transformResponse: [function (data) {
return data;
}]
}).then(function (result) {
console.log(result.data);
})
}
the Directives I have is
.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
For some reason, I am not getting the file value. On console.log() I am receiving undefined. FYI, I am just trying to grab a file. Is there something wrong in my code?
I came to that conclusion because it seems to have passing undefined to server from browser's developer tool. The screen-grab is as follows.
The problem was non binding issue with files. Angular has no support for that yet. It was solved with the solution provided here.
AngularJs: How to check for changes in file input fields?
This worked for me:
<div>
<input id="imageList" name="imageList" type="file" file-model="myFile">
</div>
I also had a json object to send with the form:
$scope.saveForm = function () {
var formData = new FormData();
var file = $scope.myFile;
formData.append("file", file);
var req = {
url: '/upload',
method: 'POST',
headers: {'Content-Type': undefined},
data: formData,
transformRequest: function (data, headersGetterFunction) {
return data;
}
};