Using Multipart without Form in Spring MVC - javascript

I had gone through many articles in stackoverflow on this specific topic, after a detailed analysis I have finally dared to post another question on the same topic.
I think this would be obvious that what I wanted to do here,
What do I want?
I want to upload a file. I am using angularjs and Spring MVC.
Source :
Controller #Spring :
#RequestMapping(value="/upload", method=RequestMethod.POST, consumes = {"multipart/form-data"})
public String handleFileUpload(#RequestParam(value = "file") MultipartFile file){
String name="";
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File(name)));
stream.write(bytes);
stream.close();
return "You successfully uploaded " + name + "!";
} catch (Exception e) {
return "You failed to upload " + name + " => " + e.getMessage();
}
} else {
return "You failed to upload " + name + " because the file was empty.";
}
}
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxUploadSize(500000000);
return multipartResolver;
}
HTML :
File to upload: <input type="file"
file-model="file" name="fd"><br /> Name: <input type="text" name="name"><br />
<br /> <input type="submit" ng-click="uploadFile()" value="Upload"> Press here to
upload the file!
JS :
$scope.uploadFile = function() {
var fd = new FormData();
var file = $scope.file;
fd.append('file', file);
$http.post("/upload",fd,
{
headers : {
'Content-Type' : undefined
}
}).success(function(data) {
debugger;
}).error(function(data) {
debugger;
})
}
Looks fair??? Here are the observations
Observations on execution:
References :
Spring MVC - AngularJS - File Upload - org.apache.commons.fileupload.FileUploadException
Javascript: Uploading a file... without a file
What is the boundary parameter in an HTTP multi-part (POST) Request?
And many more....:)
Update
Directive which is used in angular,
myApp.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]);
});
}
}
}]);
Request extracted from chrome :

Problem in my approach :
I created a bean for MultiPartResolver. My understanding after resolving the issue is like you define this bean only when you want a specific type of file or something very specific to the application. Although I seek more insight into this and would love to hear from techies of stackoverflow.
Solution for current problem:
I would give my source code,
HTML :
<div ng-controller="myCtrl">
<input type="file" file-model="myFile" />
<button ng-click="uploadFile()">upload me</button>
</div>
AngularJS :
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.controller('myCtrl', ['$scope', '$http', function($scope, $http){
$scope.uploadFile = function(){
var file = $scope.myFile;
var fd = new FormData();
fd.append('file', file);
//We can send anything in name parameter,
//it is hard coded to abc as it is irrelavant in this case.
var uploadUrl = "/upload?name=abc";
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
}]);
Spring :
#RequestMapping(value="/upload", method=RequestMethod.POST)
public String handleFileUpload(#RequestParam("name") String name,
#RequestParam("file") MultipartFile file){
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File(name)));
stream.write(bytes);
stream.close();
return "You successfully uploaded " + name + "!";
} catch (Exception e) {
return "You failed to upload " + name + " => " + e.getMessage();
}
} else {
return "You failed to upload " + name + " because the file was empty.";
}
}
And #arahant Even though we don't see any document base64 content in the request payload while sending request, angular does send MultiPartFile, here is the screenshot
Thanks to all the references. If not for these people I wouldn't have solved this problem at all.
References :
http://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs

Using MultipartHttpServletRequest would be a simple option here, which should work without any other change.
public String handleFileUpload(MultipartHttpServletRequest request) {
Map<String, MultipartFile> uploadedFiles = request.getFileMap();
//...
}

Related

How to Drop Multiple files in Dropzone.js in ASP.Net core Razorpages

Im Stuck with the problem that I can't get the "UploadMultiple" to work.
Whenever I try to Drop more than one File at once (drag and dropp 3 selected PDF files for example) I don't recieve any files in the c# controller.
The View seems to work, as there are no errors when dropping the Files.
In the controller however, I don't recieve any files (files.Count = 0).
these are my code snippets:
View HTML:
<div class="col-md-8">
<form id="fileUploadForm" class="text-center dropzone needsclick dz-clickable" method="post" enctype="multipart/form-data" style="min-height: 500px;">
</form>
</div>
JS:
Dropzone.autoDiscover = false;
$("#fileUploadForm").dropzone({
url: "/UploadView",
paramName: "files",
uploadMultiple: true,
parallelUploads: 1,
maxFilesize: 50,
init: function () {
this.on('success', function (file) {
var element = document.getElementById("submitbutton");
element.style.display = "inline";
var args = Array.prototype.slice.call(arguments);
var lowercaseName = file.name.toLowerCase()
if (!lowercaseName.includes(".pdf") && args[1] === "success") {
$("#directUploadDocs").append("<p>" + file.name + "</p><br />");
} else {
switch (args[1]) {
case "HashFailed":
$("#errorDocs").append("<div><h4>CUSTOM_TEXT</h4><p>" + file.name + "</p></div>");
break;
case "UnknownFile":
$("#errorDocs").append("<div><h4>CUSTOM_TEXT</h4><p>" + file.name + "</p></div>");
break;
case "success":
console.log("success");
break;
default:
console.log("sorry an error happened");
}
}
});
},
});
C# Controller:
public async Task<IActionResult> OnPostAsync(ICollection<IFormFile> files)
{
var directoryPath = Path.Combine(_appSettings.UploadFolder, user.SessionID);
Directory.CreateDirectory(directoryPath);
foreach (var file in files)
{
var uploadPath = Path.Combine(_appSettings.UploadFolder, user.SessionID, Guid.NewGuid().ToString() + Path.GetExtension(file.FileName));
if (file.Length > 0)
{
Do Something;
}
}
return Content("success");
}
I know that I wrote pretty custom code additional to the reccomended code from dropzone.js, but I hope its still possible to fix that Problem.
SOLVED!
SOLUTION:
Bruce Adams Posted an answer that actually worked for me:
new C# controller:
public async Task<IActionResult> OnPostAsync()
{
var directoryPath = Path.Combine(_appSettings.UploadFolder, user.SessionID);
Directory.CreateDirectory(directoryPath);
foreach (var file in Request.Form.Files)
{
var uploadPath = Path.Combine(_appSettings.UploadFolder, user.SessionID, Guid.NewGuid().ToString() + Path.GetExtension(file.FileName));
if (file.Length > 0)
{
Do Something;
}
}
return Content("success");
}

upload form with other form fiels angularjs [duplicate]

Here is my HTML form:
<form name="myForm" ng-submit="">
<input ng-model='file' type="file"/>
<input type="submit" value='Submit'/>
</form>
I want to upload an image from local machine and want to read the content of the uploaded file. All this I want to do using AngularJS.
When I try to print the value of $scope.file it comes as undefined.
Some of the answers here propose using FormData(), but unfortunately that is a browser object not available in Internet Explorer 9 and below. If you need to support those older browsers, you will need a backup strategy such as using <iframe> or Flash.
There are already many Angular.js modules to perform file uploading. These two have explicit support for older browsers:
https://github.com/leon/angular-upload - uses iframes as a fallback
https://github.com/danialfarid/ng-file-upload - uses FileAPI/Flash as a fallback
And some other options:
https://github.com/nervgh/angular-file-upload/
https://github.com/uor/angular-file
https://github.com/twilson63/ngUpload
https://github.com/uploadcare/angular-uploadcare
One of these should fit your project, or may give you some insight into how to code it yourself.
The easiest is to use HTML5 API, namely FileReader
HTML is pretty straightforward:
<input type="file" id="file" name="file"/>
<button ng-click="add()">Add</button>
In your controller define 'add' method:
$scope.add = function() {
var f = document.getElementById('file').files[0],
r = new FileReader();
r.onloadend = function(e) {
var data = e.target.result;
//send your binary data via $http or $resource or do anything else with it
}
r.readAsBinaryString(f);
}
Browser Compatibility
Desktop Browsers
Edge 12, Firefox(Gecko) 3.6(1.9.2),
Chrome 7, Opera* 12.02, Safari 6.0.2
Mobile Browsers
Firefox(Gecko) 32,
Chrome 3,
Opera* 11.5,
Safari 6.1
Note : readAsBinaryString() method is deprecated and readAsArrayBuffer() should be used instead.
This is the modern browser way, without 3rd party libraries. Works on all the latest browsers.
app.directive('myDirective', function (httpPostFactory) {
return {
restrict: 'A',
scope: true,
link: function (scope, element, attr) {
element.bind('change', function () {
var formData = new FormData();
formData.append('file', element[0].files[0]);
httpPostFactory('upload_image.php', formData, function (callback) {
// recieve image name to use in a ng-src
console.log(callback);
});
});
}
};
});
app.factory('httpPostFactory', function ($http) {
return function (file, data, callback) {
$http({
url: file,
method: "POST",
data: data,
headers: {'Content-Type': undefined}
}).success(function (response) {
callback(response);
});
};
});
HTML:
<input data-my-Directive type="file" name="file">
PHP:
if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) {
// uploads image in the folder images
$temp = explode(".", $_FILES["file"]["name"]);
$newfilename = substr(md5(time()), 0, 10) . '.' . end($temp);
move_uploaded_file($_FILES['file']['tmp_name'], 'images/' . $newfilename);
// give callback to your angular code with the image src name
echo json_encode($newfilename);
}
js fiddle (only front-end)
https://jsfiddle.net/vince123/8d18tsey/31/
Below is working example of file upload:
http://jsfiddle.net/vishalvasani/4hqVu/
In this one function called
setFiles
From View which will update the file array in controller
or
You can check jQuery File Upload using AngularJS
http://blueimp.github.io/jQuery-File-Upload/angularjs.html
You can achieve nice file and folder upload using flow.js.
https://github.com/flowjs/ng-flow
Check out a demo here
http://flowjs.github.io/ng-flow/
It doesn't support IE7, IE8, IE9, so you'll eventually have to use a compatibility layer
https://github.com/flowjs/fusty-flow.js
Use the onchange event to pass the input file element to your function.
<input type="file" onchange="angular.element(this).scope().fileSelected(this)" />
So when a user selects a file, you have a reference to it without the user needing to click an "Add" or "Upload" button.
$scope.fileSelected = function (element) {
var myFileSelected = element.files[0];
};
I tried all alternatives that #Anoyz (Correct answer) gives... and the best solution is https://github.com/danialfarid/angular-file-upload
Some Features:
Progress
Multifiles
Fields
Old browsers (IE8-9)
It's work fine for me. You just have to pay attention to instructions.
In server-side i use NodeJs, Express 4 and Multer middleware to manage multipart request.
HTML
<html>
<head></head>
<body ng-app = "myApp">
<form ng-controller = "myCtrl">
<input type = "file" file-model="files" multiple/>
<button ng-click = "uploadFile()">upload me</button>
<li ng-repeat="file in files">{{file.name}}</li>
</form>
Scripts
<script src =
"http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script>
angular.module('myApp', []).directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('change', function(){
$parse(attrs.fileModel).assign(scope,element[0].files)
scope.$apply();
});
}
};
}]).controller('myCtrl', ['$scope', '$http', function($scope, $http){
$scope.uploadFile=function(){
var fd=new FormData();
console.log($scope.files);
angular.forEach($scope.files,function(file){
fd.append('file',file);
});
$http.post('http://localhost:1337/mediaobject/upload',fd,
{
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).success(function(d)
{
console.log(d);
})
}
}]);
</script>
The <input type=file> element does not by default work with the ng-model directive. It needs a custom directive:
Working Demo of select-ng-files Directive that Works with ng-model1
angular.module("app",[]);
angular.module("app").directive("selectNgFiles", function() {
return {
require: "ngModel",
link: function postLink(scope,elem,attrs,ngModel) {
elem.on("change", function(e) {
var files = elem[0].files;
ngModel.$setViewValue(files);
})
}
}
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<h1>AngularJS Input `type=file` Demo</h1>
<input type="file" select-ng-files ng-model="fileList" multiple>
<h2>Files</h2>
<div ng-repeat="file in fileList">
{{file.name}}
</div>
</body>
$http.post from a FileList
$scope.upload = function(url, fileList) {
var config = { headers: { 'Content-Type': undefined },
transformResponse: angular.identity
};
var promises = fileList.map(function(file) {
return $http.post(url, file, config);
});
return $q.all(promises);
};
When sending a POST with a File object, it is important to set 'Content-Type': undefined. The XHR send method will then detect the File object and automatically set the content type.
Easy with a directive
Html:
<input type="file" file-upload multiple/>
JS:
app.directive('fileUpload', function () {
return {
scope: true, //create a new scope
link: function (scope, el, attrs) {
el.bind('change', function (event) {
var files = event.target.files;
//iterate files since 'multiple' may be specified on the element
for (var i = 0;i<files.length;i++) {
//emit event upward
scope.$emit("fileSelected", { file: files[i] });
}
});
}
};
In the directive we ensure a new scope is created and then listen for changes made to the file input element. When changes are detected with emit an event to all ancestor scopes (upward) with the file object as a parameter.
In your controller:
$scope.files = [];
//listen for the file selected event
$scope.$on("fileSelected", function (event, args) {
$scope.$apply(function () {
//add the file object to the scope's files collection
$scope.files.push(args.file);
});
});
Then in your ajax call:
data: { model: $scope.model, files: $scope.files }
http://shazwazza.com/post/uploading-files-and-json-data-in-the-same-request-with-angular-js/
i think this is the angular file upload:
ng-file-upload
Lightweight Angular JS directive to upload files.
Here is the DEMO page.Features
Supports upload progress, cancel/abort upload while in progress, File drag and drop (html5), Directory drag and drop (webkit), CORS, PUT(html5)/POST methods, validation of file type and size, show preview of selected images/audio/videos.
Cross browser file upload and FileReader (HTML5 and non-HTML5) with Flash polyfill FileAPI. Allows client side validation/modification before uploading the file
Direct upload to db services CouchDB, imgur, etc... with file's content type using Upload.http(). This enables progress event for angular http POST/PUT requests.
Seperate shim file, FileAPI files are loaded on demand for non-HTML5 code meaning no extra load/code if you just need HTML5 support.
Lightweight using regular $http to upload (with shim for non-HTML5 browsers) so all angular $http features are available
https://github.com/danialfarid/ng-file-upload
Your file and json data uploading at the same time .
// FIRST SOLUTION
var _post = function (file, jsonData) {
$http({
url: your url,
method: "POST",
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
var formData = new FormData();
formData.append("model", angular.toJson(data.model));
formData.append("file", data.files);
return formData;
},
data: { model: jsonData, files: file }
}).then(function (response) {
;
});
}
// END OF FIRST SOLUTION
// SECOND SOLUTION
// If you can add plural file and If above code give an error.
// You can try following code
var _post = function (file, jsonData) {
$http({
url: your url,
method: "POST",
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
var formData = new FormData();
formData.append("model", angular.toJson(data.model));
for (var i = 0; i < data.files.length; i++) {
// add each file to
// the form data and iteratively name them
formData.append("file" + i, data.files[i]);
}
return formData;
},
data: { model: jsonData, files: file }
}).then(function (response) {
;
});
}
// END OF SECOND SOLUTION
You can use a FormData object which is safe and fast:
// Store the file object when input field is changed
$scope.contentChanged = function(event){
if (!event.files.length)
return null;
$scope.content = new FormData();
$scope.content.append('fileUpload', event.files[0]);
$scope.$apply();
}
// Upload the file over HTTP
$scope.upload = function(){
$http({
method: 'POST',
url: '/remote/url',
headers: {'Content-Type': undefined },
data: $scope.content,
}).success(function(response) {
// Uploading complete
console.log('Request finished', response);
});
}
http://jsfiddle.net/vishalvasani/4hqVu/ works fine in chrome and IE (if you update CSS a little in background-image).
This is used for updating progress bar:
scope.progress = Math.round(evt.loaded * 100 / evt.total)
but in FireFox angular's [percent] data is not updated in DOM successfully,although files are uploading successfully.
You may consider IaaS for file upload, such as Uploadcare. There is an Angular package for it: https://github.com/uploadcare/angular-uploadcare
Technically it's implemented as a directive, providing different options for uploading, and manipulations for uploaded images within the widget:
<uploadcare-widget
ng-model="object.image.info.uuid"
data-public-key="YOURKEYHERE"
data-locale="en"
data-tabs="file url"
data-images-only="true"
data-path-value="true"
data-preview-step="true"
data-clearable="true"
data-multiple="false"
data-crop="400:200"
on-upload-complete="onUCUploadComplete(info)"
on-widget-ready="onUCWidgetReady(widget)"
value="{{ object.image.info.cdnUrl }}"
/>
More configuration options to play with: https://uploadcare.com/widget/configure/
I know this is a late entry but I have created a simple upload directive. Which you can get working in no time!
<input type="file" multiple ng-simple-upload web-api-url="/api/Upload" callback-fn="myCallback" />
ng-simple-upload more on Github with an example using Web API.
HTML
<input type="file" id="file" name='file' onchange="angular.element(this).scope().profileimage(this)" />
add 'profileimage()' method to your controller
$scope.profileimage = function(selectimage) {
console.log(selectimage.files[0]);
var selectfile=selectimage.files[0];
r = new FileReader();
r.onloadend = function (e) {
debugger;
var data = e.target.result;
}
r.readAsBinaryString(selectfile);
}
This should be an update/comment to #jquery-guru's answer but as I don't have enough rep it will go here. It fixes the errors that are now generated by the code.
https://jsfiddle.net/vzhrqotw/
The change is basically:
FileUploadCtrl.$inject = ['$scope']
function FileUploadCtrl(scope) {
To:
app.controller('FileUploadCtrl', function($scope)
{
Feel free to move to a more appropriate location if desired.
I've read all the thread and the HTML5 API solution looked the best. But it changes my binary files, corrupting them in a manner I've not investigated. The solution that worked perfectly for me was :
HTML :
<input type="file" id="msds" ng-model="msds" name="msds"/>
<button ng-click="msds_update()">
Upload
</button>
JS:
msds_update = function() {
var f = document.getElementById('msds').files[0],
r = new FileReader();
r.onloadend = function(e) {
var data = e.target.result;
console.log(data);
var fd = new FormData();
fd.append('file', data);
fd.append('file_name', f.name);
$http.post('server_handler.php', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
console.log('success');
})
.error(function(){
console.log('error');
});
};
r.readAsDataURL(f);
}
Server side (PHP):
$file_content = $_POST['file'];
$file_content = substr($file_content,
strlen('data:text/plain;base64,'));
$file_content = base64_decode($file_content);
I am able to upload files using AngularJS by using below code:
The file for the argument that needs to be passed for the function ngUploadFileUpload is $scope.file as per your question.
The key point here is to use transformRequest: []. This will prevent $http with messing with the contents of the file.
function getFileBuffer(file) {
var deferred = new $q.defer();
var reader = new FileReader();
reader.onloadend = function (e) {
deferred.resolve(e.target.result);
}
reader.onerror = function (e) {
deferred.reject(e.target.error);
}
reader.readAsArrayBuffer(file);
return deferred.promise;
}
function ngUploadFileUpload(endPointUrl, file) {
var deferred = new $q.defer();
getFileBuffer(file).then(function (arrayBuffer) {
$http({
method: 'POST',
url: endPointUrl,
headers: {
"accept": "application/json;odata=verbose",
'X-RequestDigest': spContext.securityValidation,
"content-length": arrayBuffer.byteLength
},
data: arrayBuffer,
transformRequest: []
}).then(function (data) {
deferred.resolve(data);
}, function (error) {
deferred.reject(error);
console.error("Error", error)
});
}, function (error) {
console.error("Error", error)
});
return deferred.promise;
}
Above accepted answer is not browser compatible. If some one has compatibility issue try this.
Fiddle
View Code
<div ng-controller="MyCtrl">
<input type="file" id="file" name="file"/>
<br>
<button ng-click="add()">Add</button>
<p>{{data}}</p>
</div>
Controller code
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.data = 'none';
$scope.add = function(){
var f = document.getElementById('file').files[0],
r = new FileReader();
r.onloadend = function(e){
var binary = "";
var bytes = new Uint8Array(e.target.result);
var length = bytes.byteLength;
for (var i = 0; i < length; i++)
{
binary += String.fromCharCode(bytes[i]);
}
$scope.data = (binary).toString();
alert($scope.data);
}
r.readAsArrayBuffer(f);
}
}
in simple words
in Html - add below code only
<form name="upload" class="form" data-ng-submit="addFile()">
<input type="file" name="file" multiple
onchange="angular.element(this).scope().uploadedFile(this)" />
<button type="submit">Upload </button>
</form>
in the controller - This function is called when you click "upload file button". it will upload the file. you can console it.
$scope.uploadedFile = function(element) {
$scope.$apply(function($scope) {
$scope.files = element.files;
});
}
add more in controllers - below code add into the function . This function is called when you click on button which is used "hitting the api (POST)". it will send file(which uploaded) and form-data to the backend .
var url = httpURL + "/reporttojson"
var files=$scope.files;
for ( var i = 0; i < files.length; i++)
{
var fd = new FormData();
angular.forEach(files,function(file){
fd.append('file',file);
});
var data ={
msg : message,
sub : sub,
sendMail: sendMail,
selectUsersAcknowledge:false
};
fd.append("data", JSON.stringify(data));
$http.post(url, fd, {
withCredentials : false,
headers : {
'Content-Type' : undefined
},
transformRequest : angular.identity
}).success(function(data)
{
toastr.success("Notification sent successfully","",{timeOut: 2000});
$scope.removereport()
$timeout(function() {
location.reload();
}, 1000);
}).error(function(data)
{
toastr.success("Error in Sending Notification","",{timeOut: 2000});
$scope.removereport()
});
}
in this case .. i added below code as form data
var data ={
msg : message,
sub : sub,
sendMail: sendMail,
selectUsersAcknowledge:false
};
<form id="csv_file_form" ng-submit="submit_import_csv()" method="POST" enctype="multipart/form-data">
<input ng-model='file' type="file"/>
<input type="submit" value='Submit'/>
</form>
In angularJS controller
$scope.submit_import_csv = function(){
var formData = new FormData(document.getElementById("csv_file_form"));
console.log(formData);
$.ajax({
url: "import",
type: 'POST',
data: formData,
mimeType:"multipart/form-data",
contentType: false,
cache: false,
processData:false,
success: function(result, textStatus, jqXHR)
{
console.log(result);
}
});
return false;
}
We have used HTML, CSS and AngularJS. Following example shows about how to upload the file using AngularJS.
<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', ['$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);
};
}]);
</script>
</body>
</html>
Working Example using Simple Directive (ng-file-model):
.directive("ngFileModel", [function () {
return {
$scope: {
ngFileModel: "="
},
link: function ($scope:any, element, attributes) {
element.bind("change", function (changeEvent:any) {
var reader = new FileReader();
reader.onload = function (loadEvent) {
$scope.$apply(function () {
$scope.ngFileModel = {
lastModified: changeEvent.target.files[0].lastModified,
lastModifiedDate: changeEvent.target.files[0].lastModifiedDate,
name: changeEvent.target.files[0].name,
size: changeEvent.target.files[0].size,
type: changeEvent.target.files[0].type,
data: changeEvent.target.files[0]
};
});
}
reader.readAsDataURL(changeEvent.target.files[0]);
});
}
}
}])
and use FormData to upload file in your function.
var formData = new FormData();
formData.append("document", $scope.ngFileModel.data)
formData.append("user_id", $scope.userId)
all credits go for
https://github.com/mistralworks/ng-file-model
I have faced a small probelm you can check it here:
https://github.com/mistralworks/ng-file-model/issues/7
Finally,here's a forked repo: https://github.com/okasha93/ng-file-model/blob/patch-1/ng-file-model.js
The code will helps to insert file
<body ng-app = "myApp">
<form ng-controller="insert_Ctrl" method="post" action="" name="myForm" enctype="multipart/form-data" novalidate>
<div>
<p><input type="file" ng-model="myFile" class="form-control" onchange="angular.element(this).scope().uploadedFile(this)">
<span style="color:red" ng-show="(myForm.myFile.$error.required&&myForm.myFile.$touched)">Select Picture</span>
</p>
</div>
<div>
<input type="button" name="submit" ng-click="uploadFile()" class="btn-primary" ng-disabled="myForm.myFile.$invalid" value="insert">
</div>
</form>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="insert.js"></script>
</body>
insert.js
var app = angular.module('myApp',[]);
app.service('uploadFile', ['$http','$window', function ($http,$window) {
this.uploadFiletoServer = function(file,uploadUrl){
var fd = new FormData();
fd.append('file', file);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(data){
alert("insert successfull");
$window.location.href = ' ';//your window location
})
.error(function(){
alert("Error");
});
}
}]);
app.controller('insert_Ctrl', ['$scope', 'uploadFile', function($scope, uploadFile){
$scope.uploadFile = function() {
$scope.myFile = $scope.files[0];
var file = $scope.myFile;
var url = "save_data.php";
uploadFile.uploadFiletoServer(file,url);
};
$scope.uploadedFile = function(element) {
var reader = new FileReader();
reader.onload = function(event) {
$scope.$apply(function($scope) {
$scope.files = element.files;
$scope.src = event.target.result
});
}
reader.readAsDataURL(element.files[0]);
}
}]);
save_data.php
<?php
require "dbconnection.php";
$ext = pathinfo($_FILES['file']['name'],PATHINFO_EXTENSION);
$image = time().'.'.$ext;
move_uploaded_file($_FILES["file"]["tmp_name"],"upload/".$image);
$query="insert into test_table values ('null','$image')";
mysqli_query($con,$query);
?>
this works
file.html
<html>
<head>
<script src = "https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
</head>
<body ng-app = "app">
<div ng-controller = "myCtrl">
<input type = "file" file-model = "myFile"/>
<button ng-click = "uploadFile()">upload me</button>
</div>
</body>
<script src="controller.js"></script>
</html>
controller.js
var app = angular.module('app', []);
app.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(res){
console.log(res);
}).error(function(error){
console.log(error);
});
}
}]);
app.controller('fileCtrl', ['$scope', 'fileUpload', function($scope, fileUpload){
$scope.uploadFile = function(){
var file = $scope.myFile;
console.log('file is ' );
console.dir(file);
var uploadUrl = "/fileUpload.php"; // upload url stands for api endpoint to handle upload to directory
fileUpload.uploadFileToUrl(file, uploadUrl);
};
}]);
</script>
fileupload.php
<?php
$ext = pathinfo($_FILES['file']['name'],PATHINFO_EXTENSION);
$image = time().'.'.$ext;
move_uploaded_file($_FILES["file"]["tmp_name"],__DIR__. ' \\'.$image);
?>
UPLOAD FILES
<input type="file" name="resume" onchange="angular.element(this).scope().uploadResume()" ng-model="fileupload" id="resume" />
$scope.uploadResume = function () {
var f = document.getElementById('resume').files[0];
$scope.selectedResumeName = f.name;
$scope.selectedResumeType = f.type;
r = new FileReader();
r.onloadend = function (e) {
$scope.data = e.target.result;
}
r.readAsDataURL(f);
};
DOWNLOAD FILES:
<a href="{{applicant.resume}}" download> download resume</a>
var app = angular.module("myApp", []);
app.config(['$compileProvider', function ($compileProvider) {
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|local|data|chrome-extension):/);
$compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|local|data|chrome-extension):/);
}]);
app.directive('ngUpload', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var options = {};
options.enableControls = attrs['uploadOptionsEnableControls'];
// get scope function to execute on successful form upload
if (attrs['ngUpload']) {
element.attr("target", "upload_iframe");
element.attr("method", "post");
// Append a timestamp field to the url to prevent browser caching results
element.attr("action", element.attr("action") + "?_t=" + new Date().getTime());
element.attr("enctype", "multipart/form-data");
element.attr("encoding", "multipart/form-data");
// Retrieve the callback function
var fn = attrs['ngUpload'].split('(')[0];
var callbackFn = scope.$eval(fn);
if (callbackFn == null || callbackFn == undefined || !angular.isFunction(callbackFn))
{
var message = "The expression on the ngUpload directive does not point to a valid function.";
// console.error(message);
throw message + "\n";
}
// Helper function to create new i frame for each form submission
var addNewDisposableIframe = function (submitControl) {
// create a new iframe
var iframe = $("<iframe id='upload_iframe' name='upload_iframe' border='0' width='0' height='0' style='width: 0px; height: 0px;
border: none; display: none' />");
// attach function to load event of the iframe
iframe.bind('load', function () {
// get content - requires jQuery
var content = iframe.contents().find('body').text();
// execute the upload response function in the active scope
scope.$apply(function () { callbackFn(content, content !== "" /* upload completed */); });
// remove iframe
if (content != "") // Fixes a bug in Google Chrome that dispose the iframe before content is ready.
setTimeout(function () { iframe.remove(); }, 250);
submitControl.attr('disabled', null);
submitControl.attr('title', 'Click to start upload.');
});
// add the new iframe to application
element.parent().append(iframe);
};
// 1) get the upload submit control(s) on the form (submitters must be decorated with the 'ng-upload-submit' class)
// 2) attach a handler to the controls' click event
$('.upload-submit', element).click(
function () {
addNewDisposableIframe($(this) /* pass the submit control */);
scope.$apply(function () { callbackFn("Please wait...", false /* upload not completed */); });
var enabled = true;
if (options.enableControls === null || options.enableControls === undefined || options.enableControls.length >= 0) {
// disable the submit control on click
$(this).attr('disabled', 'disabled');
enabled = false;
}
$(this).attr('title', (enabled ? '[ENABLED]: ' : '[DISABLED]: ') + 'Uploading, please wait...');
// submit the form
$(element).submit();
}
).attr('title', 'Click to start upload.');
}
else
alert("No callback function found on the ngUpload directive.");
}
};
});
<form class="form form-inline" name="uploadForm" id="uploadForm"
ng-upload="uploadForm12" action="rest/uploadHelpFile" method="post"
enctype="multipart/form-data" style="margin-top: 3px;margin-left:
6px"> <button type="submit" id="mbUploadBtn" class="upload-submit"
ng-hide="true"></button> </form>
#RequestMapping(value = "/uploadHelpFile", method =
RequestMethod.POST) public #ResponseBody String
uploadHelpFile(#RequestParam(value = "file") CommonsMultipartFile[]
file,#RequestParam(value = "fileName") String
fileName,#RequestParam(value = "helpFileType") String
helpFileType,#RequestParam(value = "helpFileName") String
helpFileName) { }

Angularjs formData.append is not working

Hi I am developing angularjs application. I have file upload module. I am appending file data to FormData as below.
var filesformdata = new FormData();
angular.forEach(this.pendingFiles, function (value, key) {
filesformdata.append(key, value);
});
for (var pair of filesformdata.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
This is My angular code.
angular.module('RoslpApp').factory('fileUpload', ['$http', function ($http) {
debugger;
var fileuploadurl = "http://localhost:19144/" + 'api/Customer/UploadLeaseFiles/' + 2;
var service = {
uploadUrl: fileuploadurl,
pendingFiles: [],
doUpload: doUpload
};
return service;
function doUpload() {
debugger;
var filesformdata = new FormData();
angular.forEach(this.pendingFiles, function (value, key) {
filesformdata.append(key, value);
});
for (var pair of filesformdata.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
return $http.post(this.uploadUrl, filesformdata, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
})
}
}]);
This is directive code.
myapp.directive('fileModel', ['fileUpload', function (fileUpload) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.bind("change", function (evt) {
fileUpload.pendingFiles[attrs.fileModel] = evt.target.files[0];
});
}
};
}]);
This is upload function
$scope.upload = function (filename) {
debugger;
fileUpload.doUpload().success(function (success) {
console.log(success);
});
};
This is html code.
<div class="upload-button" ng-repeat="file in files">
<div class="upload-button-icon">
<img src="images/folder-small.png">
<div class="upload-text">{{file}}</div>
<input type="file" id="file1" name="file1" file-data="{{file}}" file-model="{{file}}"/>
</div>
</div>
<input type="submit" value="{{ 'NEXT' | translate }}" class="blue-button" ng-click="upload()">
Eventough i have files in this.pendingFiles when i display using console.log or in api using below code i dont get files.
System.Web.HttpFileCollection hfc = System.Web.HttpContext.Current.Request.Files;
// CHECK THE FILE COUNT.
UploadedLeaseFiles totalDocumentInserted = null;
for (int iCnt = 0; iCnt <= hfc.Count - 1; iCnt++)
I have files inside this.pendingFiles. Please see the screen shot.
My filesformdata FormData is empty always. May i get some help here to fix this? Thanks.
The data in a FormData object filesformdata is not revealed by inspecting it with console.log(). It is there, you just can't see it. But however you can view it in networks tab under request payload.
Here is a filesInput directive that integrates with the ngModelController API:
app.directive("filesInput", function() {
return {
require: "ngModel",
link: postLink
};
function postLink(scope, elem, attrs, ngModel) {
elem.on("change", function() {
ngModel.$setViewValue(elem[0].files);
})
}
});
Usage:
<input type=file ng-model="files" files-input multiple />
Test it with:
vm.compute = function () {
var filesformdata = new FormData();
angular.forEach(vm.files, function (value, key) {
filesformdata.append(key, value);
});
for (var pair of filesformdata.entries()) {
console.log(pair[0] + ', ' + pair[1]);
console.log(pair[1]);
}
}
You will find that formData.append works.
The DEMO on PLNKR

CKEditor response callback after file attached successfully

Using CKEditor to send email and upload attachments. Below is the minimal configuration I've from this source.
CKEDITOR.replace('email.Message', {
filebrowserUploadUrl: '/Controller/UploadAttachment',
extraPlugins: 'attach', // attachment plugin
toolbar: this.customToolbar, //use custom toolbar
autoCloseUpload: true, //autoClose attachment container on attachment upload
validateSize: 30, //30mb size limit
onAttachmentUpload: function(response) {
/*
the following code just utilizes the attachment upload response to generate
ticket-attachment on your page
*/
attachment_id = $(response).attr('data-id');
if (attachment_id) {
attachment = $(response).html();
$closeButton = $('<span class="attachment-close">').text('x').on('click', closeButtonEvent)
$('.ticket-attachment-container').show()
.append($('<div>', {
class: 'ticket-attachment'
}).html(attachment).append($closeButton))
.append($('<input>', {
type: 'hidden',
name: 'attachment_ids[]'
}).val(attachment_id));
}
}
});
On the Controller side I've got below code
const string scriptTag = "<script type='text/javascript'>window.parent.CKEDITOR.tools.callFunction({0}, '{1}', '{2}')</script>";
public ContentResult UploadAttachment()
{
string basePath = HttpContext.Server.MapPath("~/assets/Images/");
const string baseUrl = #"/ckfinder/userfiles/";
var funcNum = 0;
int.TryParse(Request["CKEditorFuncNum"], out funcNum);
if (Request.Files == null || Request.Files.Count < 1)
return BuildReturnScript(funcNum, null, "No file has been sent");
if (!System.IO.Directory.Exists(basePath))
return BuildReturnScript(funcNum, null, "basePath folder doesn't exist");
var receivedFile = Request.Files[0];
var fileName = receivedFile.FileName;
if (string.IsNullOrEmpty(fileName)) {
return BuildReturnScript(funcNum, null, "File name is empty");
}
var sFileName = System.IO.Path.GetFileName(fileName);
var nameWithFullPath = System.IO.Path.Combine(basePath, sFileName);
//Note: you may want to consider using your own naming convention for files, as this is vulnerable to overwrites
//e.g. at the moment if two users uploaded a file called image1.jpg, one would clash with the other.
//In the past, I've used Guid.NewGuid() combined with the file extension to ensure uniqueness.
receivedFile.SaveAs(nameWithFullPath);
var url = baseUrl + sFileName;
return BuildReturnScript(funcNum, url, null);
}
private ContentResult BuildReturnScript(int functionNumber, string url, string errorMessage) {
return Content(
string.Format(scriptTag, functionNumber, HttpUtility.JavaScriptStringEncode(url ? ? ""), HttpUtility.JavaScriptStringEncode(errorMessage ? ? "")),
"text/html"
);
}
Below is the response I get back inside onAttachmentUpload - function
<form enctype="multipart/form-data" method="POST" dir="ltr" lang="en" action="/Controller/UploadAttachment?CKEditor=email_Message&CKEditorFuncNum=0&langCode=en">
<label id="cke_73_label" for="cke_74_fileInput_input" style="display:none"></label>
<input style="width:100%" id="cke_74_fileInput_input" aria-labelledby="cke_73_label" type="file" name="attachment" size="38">
</form>
<script>
window.parent.CKEDITOR.tools.callFunction(98);
window.onbeforeunload = function({
window.parent.CKEDITOR.tools.callFunction(99)
});
</script>
But it is expecting some data-id for attachment id. I've no idea what the response should look like. Could someone tell me what the actual response should look like and what is the data-id its expecting as attr in response? Also, is there anyway I can upload multiple files with this?
This is how I am returning the response now and rendering the attached file. Hope it might help someone in future.
[AcceptVerbs(HttpVerbs.Post)]
public ContentResult UploadAttachment() {
string basePath = HttpContext.Server.MapPath("~/somepath");
var funcNum = 0;
int.TryParse(Request["CKEditorFuncNum"], out funcNum);
if (Request.Files == null || Request.Files.Count < 1)
return Content("No file has been sent");
if (!System.IO.Directory.Exists(basePath))
Directory.CreateDirectory(Path.Combine(basePath));
var receivedFile = Request.Files[0];
var fileName = receivedFile.FileName;
if (string.IsNullOrEmpty(fileName)) {
return Content("File name is empty");
}
var sFileName = System.IO.Path.GetFileName(fileName);
var nameWithFullPath = Path.Combine(basePath, sFileName);
receivedFile.SaveAs(nameWithFullPath);
var content = "<span data-href=\"" + nameWithFullPath + "\" data-id=\"" + funcNum + "\"><i class=\"fa fa-paperclip\"> </i> " + sFileName + "</span>";
return Content(content);
}
and on the JS side I have below code to append the uploaded file name:
CKEDITOR.replace('email.Message', {
filebrowserUploadUrl: '/Controller/UploadAttachment',
extraPlugins: 'attach', // attachment plugin
toolbar: this.customToolbar, //use custom toolbar
autoCloseUpload: true, //autoClose attachment container on attachment upload
validateSize: 30, //30mb size limit
onAttachmentUpload: function(response) {
/*
the following code just utilizes the attachment upload response to generate
ticket-attachment on your page
*/
attachment_id = $(response).attr('data-id');
if (attachment_id) {
attachment = response;
$closeButton = '<span class="attachment-close btn btn-danger float-right" style="margin-top:-7px"><i class="fa fa-trash"></i></span>'; //.on('click', closeButtonEvent)
$respDiv = '<ol class="breadcrumb navbar-breadcrumb" style="padding:18px 15px"><li style="display:block">' + attachment + $closeButton + '</li></ol>';
$('.ticket-attachment-container').show()
.append($('<div>', {
class: 'ticket-attachment'
}).html($respDiv))
.append($('<input>', {
type: 'hidden',
name: 'attachment_ids[]'
}).val(attachment_id));
$('.ticket-attachment-container').on('click', '.attachment-close', function() {
$(this).closest('.ticket-attachment').remove();
if (!$('.ticket-attachment-container .ticket-attachment').length)
$('.ticket-attachment-container').hide();
});
}
}
});

Unable to upload multiple files with SAP UI5 FileUploader

I'm using the following code to upload multiple documents to the server.
var docFileUploader = new sap.ui.unified.FileUploader({
name : fileUploaderName,
uploadOnChange: false,
uploadUrl: uploadUrlStr,
multiple:true,
additionaldata : nodeObjId ,
fileSizeExceed: function (oEvent) {
var sName = oEvent.getParameter("fileName");
var fSize = oEvent.getParameter("fileSize");
var fLimit = oFileUploader.getMaximumFileSize();
Messenger().post({
message: "File: " + sName + " is of size " + fSize + " MB which exceeds the file size limit of " + fLimit + " MB.",
type: 'error',
showCloseButton: true
});
},
uploadComplete: function (oEvent) {
var sResponse = oEvent.getParameter("response");
console.log(sResponse);
var thisDlg = this.getParent().getParent().getParent().getParent();
console.log(thisDlg);
if (sResponse) {
var m = /^\[(\d\d\d)\]:(.*)$/.exec(sResponse);
if (m[1] == "200") {
uploadSuccess = true;
thisDlg.setBusy(false);
console.log("The document has been uploaded successfully");
setTimeout(function() { Messenger().post("The document has been uploaded successfully");}, 100);
}
else {
thisDlg.setBusy(false);
setTimeout(function() { Messenger().post({
message: 'Oops! Error in document upload. <br>Please try again or contact your administrator.',
type: 'error',
showCloseButton: true
});},100);
}
}
thisDlg.setBusy(false);
console.log("The document has been uploaded successfully");
setTimeout(function() { Messenger().post("The document has been uploaded successfully");}, 100);
thisDlg.close();
thisDlg.destroy();
setTimeout(function() { reloadPage(attrGrpName); }, 100);
}
});
The controller part is as below:
#RequestMapping(value = "doc/upload", method = RequestMethod.POST, consumes = "multipart/form-data")
public #ResponseBody String uploadDoc(#RequestParam("uploadDoc-data") ObjectId nodeId,
#RequestParam(value = "uploadDoc", required = true) MultipartFile[] files, #RequestParam String userId, #RequestParam String passwd) {
if (files != null) {
return service.uploadDoc(nodeId, files[0], userId, passwd);
} else
return "No files found to upload";
}
Even if I use files[0] gives me an ArrayIndexOutofBound 0 Exception. It means the MultipartFile[] is returning an empty array only. I was able to upload one file without multiple attributes. The problem arises if I set the multiple attributes to 'true'. What am I missing? Please help me.

Categories

Resources