Search code examples
angularjsgrailsangular-file-upload

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..


Solution

  • 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);