Angular JS File upload Content Disposition - javascript

I am new to Angular JS and trying my hands on File upload.
My requirement is to submit the multipart data on button click.
I read on ng-model not working on type="file", so I got to know the work around and i copied the directive. after working through that directive, while sending data there is no Content-disposition data set. I mean file name, content type etc which I want to read at server side.
that is why I am getting null at headerOfFilePart.getFileName()
what I am doing wrong. what is the right way to achieve things i described above in Angular JS.
<div ng-controller="uploadController">
<h2> Add Order </h2>
Enter your Name:
<input type="text" name="name" ng-model="myName"/>
<input type="file" fileread="vm.uploadme" />
<input type="button" name="button" ng-click='uploadFile()'/>
</div>
And this is my JS part
validationApp.controller('uploadController', function($scope,$http,$location,$window) {
$scope.uploadFile = function() {
var fd = new FormData();
//Take the first selected file
fd.append("file", $scope.vm.uploadme);
fd.append("name", $scope.myName);
uploadUrl = "http://localhost:8080/IPOCCService/rest/UserManager/upload1";
$http.post(uploadUrl, fd, {
withCredentials: true,
headers: {'Content-Type': undefined },
transformRequest: angular.identity
}).
success(function(data, status, headers, config) {
alert(data);
}).
error(function(data, status, headers, config) {
alert("failure");
});
};
});
validationApp.directive("fileread", [function () {
return {
scope: {
fileread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
var reader = new FileReader();
reader.onload = function (loadEvent) {
scope.$apply(function () {
scope.fileread = loadEvent.target.result;
});
};
reader.readAsDataURL(changeEvent.target.files[0]);
});
}
};
}]);
REST JAVA
#POST
#Path("/upload1")
#Produces({ MediaType.APPLICATION_JSON} )
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response responseMsg3(FormDataMultiPart form) {
System.out.println("File Uploaded");
FormDataBodyPart filePart1 = form.getField("name");
System.out.println(filePart1.getName() + " = " +filePart1.getValue());
FormDataBodyPart filePart = form.getField("file");
ContentDisposition headerOfFilePart = filePart.getContentDisposition();
InputStream fileInputStream = filePart.getValueAs(InputStream.class);
String filePath = SERVER_UPLOAD_LOCATION_FOLDER + headerOfFilePart.getFileName();
// save the file to the server
saveFile(fileInputStream, filePath);
String output = "File saved to server location : " + filePath;
return Response.status(200).entity("true").build();
}

When you use FileReader to read your files, only the contents of the file is assigned to your scope:
scope.fileread = loadEvent.target.result;
In your case, just simply assign the file to your scope:
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
scope.$apply(function(){
scope.fileread = changeEvent.target.files[0];
// changeEvent.target.files[0] is an HTML5 file object which contains ALL
// information about the file including fileName, contents,...
// scope.fileread is now assigned the selected file
});
});
}

app.directive('fileRead', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileread);
var modelSetter = model.assign;
element.bind('change', function(){
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.readAsDataURL(input.files[0]);
}
}
readURL(this);
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
<input type="file" file-read="vm.uploadme" />
this directive works for me.

You can use the module ng-file-upload it's a directive that do everythinh about file upload See here

Related

Angular upload onchange event :getting empty file in server

Here is my code to upload file to server on input change
$scope.uploadImage = function (f) {
$http.post('/art',{'image':f},{headers: {'Content-Type': undefined}}).then(function (response) {
console.log(response);
});
}
but i will get empty files in server however i check my serverside code with normal fileupload it works fine without any problem
Serverside
//get empty in angular upload
console.log(req.file('image'));
req.file('image').upload({
// don't allow the total upload size to exceed ~10MB
maxBytes: 10000000
},function whenDone(err, uploadedFiles) {
return res.json({
'status':uploadedFiles
})
});
HTML
<input type="file" ng-model="art.artImage" onchange="angular.element(this).scope().uploadImage(this.files)" name="artImage" id="artImage">
I believe its problem with content-type in angular http post request
when the input type is file file will not attach the model. You need a workaround like this.
.directive("fileread", [function () {
return {
scope: {
fileread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
var reader = new FileReader();
reader.onload = function (loadEvent) {
scope.$apply(function () {
scope.fileread = loadEvent.target.result;
});
}
reader.readAsDataURL(changeEvent.target.files[0]);
});
}
}
}]);
change the input like
<input type="file" fileread="art.artImage" onchange="angular.element(this).scope().uploadImage(this.files)"
name="artImage" id="artImage">
use the multipart header in your request
$http.post('/art', {
'image': art.artImage
}, {
transformRequest: angular.identity,
headers: {
'Content-Type': "multipart/form-data"
}
})
Use ng-fileUpload lib for angularjs
My HTML
<form method="post" enctype="multipart/form-data" ng-controller="commentCtrl" name="form">
<img src="source/assets/images/icons/icofileattached.png" class="attachmentpng-height" ngf-select="uploadFiles($file)" ng-model="files"/>
<md-button type="submit" class="md-raised custom-submit-button" ng-click="MakeComments()"> SUBMIT </md-button>
</form>
My Controller code
$scope.uploadFiles = function(file) {
console.log(file);
$scope.fileData = file;
var fd = new FormData();
fd.append('file', file);
Restangular.one('/api/files/end points').withHttpConfig({transformRequest: angular.identity})
.customPOST(fd, '', undefined, {'Content-Type': undefined})
};
Please try this , avoid using onload in HTML tag for file :
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/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', ['$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(){
alert("Done");
})
.error(function(){
alert("Sorry");
});
}
}]);
myApp.controller('myCtrl', ['$scope', 'fileUpload', function($scope, fileUpload){
$scope.uploadFile = function(){
var file = $scope.myFile;
console.log('file is ' );
console.dir(file);
var uploadUrl = "/art";
fileUpload.uploadFileToUrl(file, uploadUrl);
};
}]);
</script>
</body>
</html>

Upload multiple files via AngularJS to Laravel Controller

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

How can I send Image data through JSON from an Image Tag that has blob URL in src?

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 {
}
});;
}

Input type file is not clearing up when successfully submitting the form

When i am submitting the form the input text is clearing up but the uploaded file is not clearing. I have used $scope.addAnswerForm.$setPristine(); but this is not working.
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]);
});
});
}
};
}
]);
app.controller("MyCtrl", function($scope, $http) {
$scope._answer = {
text: '',
comment_pic: ''
};
$scope.__answer = JSON.parse(JSON.stringify($scope._answer));
$scope.addAnswer = function(todo) {
var data = {
answer: $scope.__answer.text,
comment_pic: $scope.__answer.comment_pic,
};
var fd = new FormData();
for (var key in data) {
fd.append(key, data[key])
};
$http({
url: '/posturl'
data: fd,
method: "POST",
headers: {
'Content-Type': undefined
}
}).success(function(data, status) {
todo.answers.push($scope.__answer);
$scope._answer.comment_pic = "";
$scope.__answer = JSON.parse(JSON.stringify($scope._answer));
});
};
});
<div ng-controller="myCtrl">
<form name="addAnswerForm">
<input ng-model="__answer.text" />
<input type="file" file-model="__answer.comment_pic" />
<button type="submit" ng-click="addAnswer(discussion)">Post</button>
</form>
</div>
how to make the form clear after submitting the form
This the file in the input type="file" is not getting cleared
By clearing the DOM of the form the form is getting cleared.
document.getElementById("MyformId").reset();
if there is another method do tell

Angular JS "form Multi-part" file upload sending Undefined value to server. Cannot upload file to Java Server

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;
}
};

Categories

Resources