File upload using Angular js and grails - angularjs

I am trying to implement a file upload using angular js and grails. I am able to call the grails controller method but not able to get the file from angular js using request.getFile() method. Here is my html code,
<script src="angular-file-upload-shim.min.js"></script>
<script src="angular.min.js"></script>
<script src="angular-file-upload.min.js"></script>
<div ng-controller="MyCtrl">
<input type="text" ng-model="myModelObj">
<input type="file" name="file" ng-file-select="onFileSelect($files)" >
<div ng-file-drop="onFileSelect($files)" ng-file-drag-over-class="optional-css-class"
ng-show="dropSupported">drop files here</div>
<div ng-file-drop-available="dropSupported=true"
ng-show="!dropSupported">HTML5 Drop File is not supported!</div>
<button ng-click="upload.abort()">Cancel Upload</button>
</div>
Here is the javascript code,
//inject angular file upload directives and service.
angular.module('myApp', ['angularFileUpload']);
var MyCtrl = [ '$scope', '$upload', function($scope, $upload) {
$scope.onFileSelect = function($files) {
//$files: an array of files selected, each file has name, size, and type.
for (var i = 0; i < $files.length; i++) {
var file = $files[i];
$scope.upload = $upload.upload({
url: 'GrailsApp/upload', //upload.php script, node.js route, or servlet url
data: {myObj: $scope.myModelObj},
file: file, // or list of files: $files for html5 only
}).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
}).success(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
}
};
}];
Here is the grails controller upload method,
def upload() {
def f = request.getFile('file')
if (f.empty) {
flash.message = 'file cannot be empty'
render(view: 'uploadForm')
return
}
f.transferTo(new File('D:/Filestorage/myfile.txt')) response.sendError(200, 'Done') }
While running this code gives a error like below,
Request.getFile() is applicable for argument types: (java.lang.String) values: {"file"}
But definitely it is going inside the controller method. Just not able to get the file from angular js.
But the same code works when I use a gsp form like below,
<g:uploadForm action="upload">
<input type="file" name="file" />
<input type="submit" />
</g:uploadForm>
The same code works like a chram and upload the file successfully.

Docs say the fileName by default is file but add fileFormDataName: "myFile" explicitly as:
$scope.upload = $upload.upload({
url: 'GrailsApp/upload', //upload.php script, node.js route, or servlet url
data: {myObj: $scope.myModelObj},
file: file,
fileFormDataName: "myFile"
}).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
}).success(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
in angular and then get the file as
request.getFile('myFile')
in Grails side to see if it works.
Also see, instead of explicitly adding a fileFormDataName just rectify that you have removed the trailing , from file: file, and use as earlier, if that helps.

The issue has been fixed. Just need to bind the post with a name, by adding fileFormDataName:"file" in the $scope.upload method.
Here is a sample,
//inject angular file upload directives and service.
angular.module('myApp', ['angularFileUpload']);
var MyCtrl = [ '$scope', '$upload', function($scope, $upload) {
$scope.onFileSelect = function($files) {
//$files: an array of files selected, each file has name, size, and type.
for (var i = 0; i < $files.length; i++) {
var file = $files[i];
$scope.upload = $upload.upload({
url: 'GrailsApp/upload', //upload.php script, node.js route, or servlet url
data: {myObj: $scope.myModelObj},
file: file,
fileFormDataName:'file'
}).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
}).success(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
}
};
}];

Related

Angularjs and laravel file upload on form submission

I am a newbie to angularjs and I want to create a form with a file. How can I get the file on angularjs controller and pass it to the laravel?
Take a look to the ng-file-upload is very easy to configure and use and there are some examples for the server side code (also PHP).
If you are using bower, install runnig:
bower install ng-file-upload --save
and add the ngFileUpload to your module:
var app = angular.module('myApp', [
// other dependencies here
'ngFileUpload'
]);
HTML:
<div class="button" ngf-select ngf-change="upload($files)">Upload on file change</div>
Controller:
$scope.upload = function (files) {
if (files && files.length) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: 'upload/url', // change this with the url/route of your laravel action
fields: {'username': $scope.username}, // this is an example to pass additional fields to pass in the post
file: file
}).progress(function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name);
}).success(function (data, status, headers, config) {
console.log('file ' + config.file.name + 'uploaded. Response: ' + data);
alert('file uploaded!');
});
}
}
};
See the demo fiddle

File upload in Grails application using angular js

I'm working on a Grails (2.3.7) application with AngularJS. I've to upload files in my application. Since the front end is managed by Angular , I'm uploading my file from Angular controller. I've gone through This
and this discussions , and tried to upload as follows.
My file uploader is
<input type="file" ng-file-select="onFileSelect($files)">
Angular controller is
myapp.controller('createWebController',['$scope','$http','$upload',function($scope,$http,$upload){
$scope.onFileSelect = function($files) {
var file = $files[0];
console.log(file)
$upload.upload({
url: 'UploadLogo/upload', //upload.php script, node.js route, or servlet url
file: file,
method: 'POST' ,
fileFormDataName: "myFile",
}).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
}).success(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
})
.error(function(data){ console.log(data)})
;
};
}])
on the server , I'm using this service and the upload handler code is
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.MultipartFile
import org.codehaus.groovy.grails.web.context.ServletContextHolder
class UploadLogoController {
FileUploadService fileUploadService
def upload() {
def avatarImage = request.getFile('file')
if (!avatarImage.isEmpty())
{
userInstance.avatar = fileUploadService.uploadFile(avatarImage, "logo.png", "~/Desktop/upload")
render "ok"
}
else
{
render "Empty"
}
}
}
But the problem is I'm getting a 500 (Internal Server Error) from grails. The file is not being uploaded.
also getting response as Cannot invoke method isEmpty() on null object
Which means the file has not been sent to the server. Whats the problem here.. Please help..
Try this way. You could create a custom directive for the file upload control
myapp.directive('ngFileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.ngFileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};}])
and in your html use <input type="file" ng-file-model="myFile" />
Then you could create a custom service to do the file upload. Note that its not necessary to create service but it can easily reuse in later file uploads just by injecting the service.
myapp.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file, uploadUrl,filename){
var fd = new FormData();
fd.append('file', file);
fd.append('filename', filename);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(data){
console.log(data)
})
.error(function(data){ console.log(data)
});
};}]);
The uploadFileToUrl takes 3 arguments , the file itself , the URL to upload and the file name to be saved as.(You can customize this as you wish) . Use the $http.post to post data.
Finally in your controller , include this
var file = $scope.myFile;
var filename = 'YourFileName'
var uploadUrl = '/UploadLogo/upload' // don't forget to include the leading /
fileUpload.uploadFileToUrl(file, uploadUrl,filename);

file upload in sails

i want to know, how to use upload files code in sails using angular upload
this is code for angular
var app = angular.module('app', ['angularFileUpload']);
app.controller('ImageCtrl', ['$scope', '$upload', function ($scop
e, $upload) {
$scope.$watch('files', function () {
$scope.upload($scope.files);
});
$scope.upload = function (files) {
window.alert(JSON.stringify(files));
if (files && files.length) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
$upload.upload({
url: '???????',
fields: {
'username': $scope.username
},
file: file
}).progress(function (evt) {
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
console.log('progress: ' + progressPercentage + '% ' +
evt.config.file.name);
}).success(function (data, status, headers, config) {
console.log('file ' + config.file.name + 'uploaded. Response: ' +
JSON.stringify(data));
});
}
}
};
}]);
in above code , what i should give url ? , my requirement is, i want to upload files in locally using sails mongodb.
Any one please share the server side nodejs code..
Sails have built-in streaming file uploads utility called skipper. In general you can upload files from angular to any sails endpoint. Then you just need to perform something like this in your controller:
req.file('avatar').upload(function (err, uploadedFiles){
if (err) return res.send(500, err);
return res.send(200, uploadedFiles);
});
You can also pass skipper options:
req.file('avatar').upload({
// ...any other options here...
}, ...);
If you aplication should upload files frequently I would recommend you to create service for this based on skipper API.

Converting php file upload end point to node.js/express

Sorry i havent used file uploads in node.js before
Currently i cam using angular service that uses FormData and submits a $http post request to php and there it is uploaded with move_uploaded_file() that is working fine
Angular .js code
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 ' + JSON.stringify(file));
var uploadUrl = "upload.php";
fileUpload.uploadFileToUrl(file, uploadUrl);
};
}]);
html
<input type="file" file-model="myFile"/>
<button ng-click="uploadFile()">upload me</button>
How can i get this into node.js express route?
i have read other questions on stack overflow but i cant quite get it that were will the data be going in res.body? or res.files and how to finnaly upload them
my undesrtandings about it is that it will be something like this
routes.post("/upload",function(req,res,next){
console.log(req.Files);
console.log(req.body);
});

angularjs and spring mvc - upload multiple files in one request

I want to implement file uploading in my web application, I am using angular.js on client side and spring mvc on server side.
I managed to get single file upload and multiple file upload working by using https://github.com/danialfarid/angular-file-upload. The thing is, when I upload multiple files each one of them is coming to me as separate request (which is obvious event after reading example code):
//inject angular file upload directives and service.
angular.module('myApp', ['angularFileUpload']);
var MyCtrl = [ '$scope', '$upload', function($scope, $upload) {
$scope.onFileSelect = function($files) {
//$files: an array of files selected, each file has name, size, and type.
for (var i = 0; i < $files.length; i++) {
var $file = $files[i];
$scope.upload = $upload.upload({
url: 'server/upload/url', //upload.php script, node.js route, or servlet url
// method: POST or PUT,
// headers: {'headerKey': 'headerValue'}, withCredential: true,
data: {myObj: $scope.myModelObj},
file: $file,
//(optional) set 'Content-Desposition' formData name for file
//fileFormDataName: myFile,
progress: function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
}
}).success(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
})
//.error(...).then(...);
}
}
}];
there is an iteration through all the files.
Now I am wondering if it is possible to somehow upload multiple files as one, single request.
on spring controller side create
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public String save(#ModelAttribute("filesForm") FileUploadForm filesForm) {
List<MultipartFile> files = filesForm.getFiles();
//do something
}
public class FileUploadForm
{
private List<MultipartFile> files;
// geters and setters ...
}
on client side upload service
return {
send: function(files) {
var data = new FormData(),
xhr = new XMLHttpRequest();
xhr.onloadstart = function() {
console.log('Factory: upload started: ', file.name);
$rootScope.$emit('upload:loadstart', xhr);
};
xhr.onerror = function(e) {
$rootScope.$emit('upload:error', e);
};
xhr.onreadystatechange = function(e)
{
if (xhr.readyState === 4 && xhr.status === 201)
{
$rootScope.$emit('upload:succes',e, xhr, file.name ,file.type);
}
};
angular.forEach(files, function(f) {
data.append('files', f, f.name);
});
xhr.open('POST', '../upload');
xhr.send(data);
}
};

Resources