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} });
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
Browse files button
<input type="file" upload-files multiple />
Create Button
<button class="btn btn-link" ng-click="store()" >Create</button>
Directive
myApp.directive('uploadFiles', function () {
return {
scope: true,
link: function (scope, element, attrs) {
element.bind('change', function (event) {
var files = event.target.files;
for (var i = 0; i < files.length; i++) {
scope.$emit("seletedFile", { file: files[i] });
}
});
}
};
});
Listen for the file selected
$scope.files = [];
$scope.$on("seletedFile", function (event, args) {
console.log("event is ", event);
console.log("args is ", args);
$scope.$apply(function () {
$scope.files.push(args.file);
});
});
Post data and selected files.
$scope.store = function() {
$scope.model = {
name: $scope.name,
type: $scope.type
};
$http({
method: 'POST',
url: '/image/store',
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
console.log("data coming into the transform is ", data);
var formData = new FormData();
formData.append("model", angular.toJson(data.model));
for (var i = 0; i < data.files; i++) {
formData.append("file" + i, data.files[i]);
}
return formData;
},
data: { model: $scope.model, files: $scope.files }
})
.then(function successCallback(response) {
console.log("%cSuccess!", "color: green;");
console.log(response);
$scope.refresh();
$scope.showModal = false;
}, function errorCallback(response) {
console.log("%cError", "color: red;");
console.log(response);
});
};
Result
In my console, I don't see my files got pass on to my controller in the back-end.
array:1 [
"model" => "{"type":"wedding"}"
]
Questions
What steps did I forget?
How would one go about and debug this further ?
I've done several angular 1 projects and also find it is not simple to upload files via $http api. Hope below code snippet which i used in my projects may help you.
$scope.store = function() {
var formData = new FormData();
// add normal properties, the name should be the same as
// what you would use in a html form
formData.append('model[name]', $scope.name);
formData.append('model[type]', $scope.type);
// add files to form data.
for (var i = 0; i < $scope.files; i++) {
formData.append('file' + i, $scope.files[i]);
}
// Don't forget the config object below
$http.post('/image/store', formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).then(function() {
// ...
});
};
Here some suggestions for you:
Make the Content-type sets to multipart/form-data to set the content type to something like.... "it has some part in it, please make sure you get it properly" thing.
Use Axios. Here's a working examples (if you didn't use Axios, this example are good too). Example to Axios on Uploading File.
You can use FormData instead
var formData = new FormData();
formData.append('model[var]', $scope.var);
// For add to the FormData other file
for (var i = 0; i < $scope.files; i++) {
formData.append('file' + i, $scope.files[i]);
}
// POST REQUEST MUST BE:
$http.post('url', formData, {
transformRequest: angular.identity, //It is for allowing files
headers: {'Content-Type': undefined}
}).then(function(response)
{
// verify if response get 200
});
I am not very experienced in Angular, so I'm assuming that your front-end works.
Debugging Tip Create a PHP file called...I dunno...file_dump.php. In that file, put this code:
<?php
echo "<pre>"
print_r($_REQUEST)
echo "</pre>"
?>
and submit your form to that. That will show you all your request data. If you do not see your files in the output, it is a problem with your JavaScript. Since I am not that good at Angular, I'm going to point you to this link: link to multiple file upload tutorial using Angular.
These guys seem to know what they're doing.
If you do see your files in the file_dump.php output, it's a problem with your backend - Laravel. This, I can help you with, but I need to see your scripts for me to be helpful in this aspect.
Please do post the results of file_dump.php.
Also, are you using the correct methods for fetching files? Link. If not, then we have found our culprit...
=D
Pranav
It is my directive:
app.directive('fileModel', ['$parse', 'message', function ($parse, message) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
//This part is for validate file type in current case must be image
element.bind('change', function (e) {
if (attrs.onlyImages == 'true') {
if (element[0].files[0].name.substring(element[0].files[0].name.lastIndexOf('.')) != '.jpg'
&& element[0].files[0].name.substring(element[0].files[0].name.lastIndexOf('.')) != '.jpeg'
&& element[0].files[0].name.substring(element[0].files[0].name.lastIndexOf('.')) != '.png'
&& element[0].files[0].name.substring(element[0].files[0].name.lastIndexOf('.')) != '.gif'
&& element[0].files[0].name.substring(element[0].files[0].name.lastIndexOf('.')) != '.bmp'
) {
message.error("This field only accept files of type images(jpg,png)");
element.attr('is_valid', false);
return false;
} else {
element.attr('is_valid', true);
}
}
scope.$apply(function () {
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
the html:
<input type="file" only-images="true" file-model="data.image" >
And Js Controller fragment:
var fd = new FormData();
fd.append('fileImage', data.image);
$http.post('http://url.com', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined,}
})
On laravel to get and copy image: is clear on the docs
https://laravel.com/docs/5.4/requests#files
I am working on a project that uses Angularjs for the FrontEnd and Java Webservices in the backend. I am trying to upload and send an Image through JSON.
The Images when uploaded, generates a blob url ( blob:http://localhost/a34ac19f-3320-4cdf-b30f-e1b0a0e7a745 ) in src. How can I read it and convert it to Base64 or other types that can be sent through JSON?
First of all add this custom directory right below your controller :
app.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]);
});
});
}
};
}]);
Then in you view use it like this :
<input type = "file" name="files" file-model = "myFile"/>
In your controller function when youf form will submitted :
Do it like this :
$scope.formSubmit = function(){
var file = $scope.myFile;
var fd = new FormData();
fd.append('profilepic', file);
fd.append('action', 'add');
$http.post('yourjavafile', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).success(function (response) {
if (response) {
} else {
}
});;
}
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;
}
};
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);