Uploading a file with AngularJS and bluimp on success callback of another form

21,042

Blueimp has an AngularJS version of jQuery File Upload available.

It includes a fileUpload directive and a FileUploadController with a submit() method that you can call manually.

You can see a working version at http://blueimp.github.io/jQuery-File-Upload/angularjs.html.

One thing you should pay attention to: make sure you load all .js files from the example in the correct order to avoid problems (cf. source of the example page).

Hope that helps!


UPDATE AFTER YOUR COMMENT:

When using the AngularJS version of jQuery File Upload, you create a form tag with the file-upload attribute like this:

<!-- Create a file upload form with options passed in from your scope -->
<form data-file-upload="options" data-ng-controller="YourController">

    <!-- This button will trigger a file selection dialog -->
    <span class="btn btn-success fileinput-button" ng-class="{disabled: disabled}">
        <span>Add files...</span>
        <input type="file" name="files[]" multiple="" ng-disabled="disabled">
    </span>

    <!-- This button will start the upload -->
    <button type="button" class="btn btn-primary start" data-ng-click="submit()">
        <span>Start upload</span>
    </button>

<form>

Then in your controller you can assign the options for the jQuery File Upload like this:

angular.module('yourModule')
    .controller('YourController', [$scope, function($scope){

        // Options you want to pass to jQuery File Upload e.g.:
        $scope.options = {
            maxFileSize: 5000000,
            acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i
        };
    }]);

You can assign the submit() handler to any ng-click attribute as long as it is inside the form (and thus can access the method).

Let me know if you need further help...


EXTRA SAMPLE CODE FOR SUCCESS CALLBACK:

If you need to run a callback function after all uploads have been completed, you can listen to the fileuploadstop event that is broadcasted by Blueimp:

// Listen to fileuploadstop event
$scope.$on('fileuploadstop', function(){

    // Your code here
    console.log('All uploads have finished');
});

Hope that helps!

Share:
21,042
Oleg Belousov
Author by

Oleg Belousov

Founder of https://n.exchange - the fastest and easiest API for instant crypto exchange

Updated on September 09, 2020

Comments

  • Oleg Belousov
    Oleg Belousov almost 4 years

    I have followed the following tutorial in order to integrate the notorious bluimp jQuery file uploader in my AngularJS project.

    After some research I found that in the options array, witihn the jquery.fileuploader.js file, there is an option called autoUpload, which when set to true upload the file automatically. I tried to disable it(false, undefined), but quickly I learned out that this causes the upload not to function at all, not even on the form submit.

    I need to trigger the upload manually, say within another callback, or by a click event. can that be done?.

    code:

    app.directive("fileupload", function() {
        return {
          restrict: "A",
          scope: {
            done: "&",
            progress: "&",
            fail: "&",
            uploadurl: "=",
            customdata: "&"
          },
          link: function(scope, elem, attrs) {
            var uploadOptions;
            uploadOptions = {
              url: scope.uploadurl,
              dataType: "json"
            };
            if (scope.done) {
              uploadOptions.done = function(e, data) {
                return scope.$apply(function() {
                  return scope.done({
                    e: e,
                    data: data
                  });
                });
              };
            }
            if (scope.fail) {
              uploadOptions.fail = function(e, data) {
                return scope.$apply(function() {
                  return scope.fail({
                    e: e,
                    data: data
                  });
                });
              };
            }
            if (scope.progress) {
              uploadOptions.progress = function(e, data) {
                return scope.$apply(function() {
                  return scope.progress({
                    e: e,
                    data: data
                  });
                });
              };
            }
            return elem.fileupload(uploadOptions).bind("fileuploadsubmit", function(e, data) {
              return data.formData = {
                    JSON.stringify(scope.customdata())
              };
            });
          }
        };
      });
    app.service('uploadService', function(authService) {
        var initializeFn, processFn;
        initializeFn = function(e, data, process) {
          var upload;
          return upload = {
            message: '',
            uploadurl: authService.getBaseUrl() + '/applications/',
            status: false
          };
        };
        processFn = function(e, data, process) {
          var file, upload;
          upload = {};
          upload.successData = [];
          upload.status = true;
          upload.error = false;
          if (process === 'done') {
            upload.message = data.result.result;
            console.log(data);
            file = data.result.resume;
            upload.successData = {
              // name: file.name,
              // fullUrl: file.url,
              // thumbUrl: file.thumbnail_url
            };
          } else if (process === 'progress') {
            upload.message = 'Uploading....!!!';
          } else {
            upload.error = true;
            upload.message = 'Please try again';
            console.log(e, data);
          }
          return upload;
        };
        return {
          process: processFn,
          initialize: initializeFn
        };
    
      });
    
    app.controller('applyCtrl', function($scope, $routeParams, uploadService){
            $scope.model.formData = {};
            $scope.model.formData.job = $routeParams.jobId;
            $scope.uploadLayer = function(e, data, process) {
              return $scope.uploadReturn = uploadService.process(e, data, process);
            };
            $scope.customData = function() {
                return $scope.model.formData;
            };
            return $scope.uploadReturn = uploadService.initialize();
    
    });
    

    view:

        <form class="applyForm" ng-submit="uploadLayer(e, data, 'progress')">
            <fieldset>
                <div class="formLine">
                    <div class="wideFieldContainer">
                        <input id="testUpload" type="file" fileupload customdata="customData()" name="resume" uploadurl="uploadReturn.uploadurl" done="uploadLayer(e, data, 'done')" fail="uploadLayer(e, data, 'fail')" progress="uploadLayer(e, data, 'progress')" />
                    </div>
                </div>
                        </fieldset>
                 </form>
    

    scripts loading order:

    ...
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script src="lib/angular/angular.js"></script>
        <script src="lib/angular/angular-resource.js"></script>
        <script src="js/app.js"></script>
        <script src="js/services.js"></script>
        <script src="js/controllers.js"></script>
        <script src="js/filters.js"></script>
        <script src="js/directives.js"></script>
        <script src="lib/bluimp/js/vendor/jquery.ui.widget.js"></script>
        <script src="lib/bluimp/js/jquery.piframe-transport.js"></script>
         <script src="lib/bluimp/js/jquery.fileupload.js"></script>   
    </body>
    </html>
    
  • Oleg Belousov
    Oleg Belousov almost 11 years
    Is there anyway to integrate this submit method in my current code?
  • Oleg Belousov
    Oleg Belousov almost 11 years
    Well, it doesn't work with my existent code, which leaves me no choice but to use the more heavy full version of the up loader, which I figured out by myself prior to asking this question. Please take a moment to observe the code and the instruction at the link that is included within my question. Thank you for you time & help
  • jvandemo
    jvandemo almost 11 years
    The AngularJS version of jQuery File Upload contains all directives and controllers you need to get the example working. Do you see an error when you try to run it? Can you create a plnkr so we can edit it? Thanks!
  • Oleg Belousov
    Oleg Belousov almost 11 years
    Here is a plunker: plnkr.co/edit/dMfWj2?p=preview My goal id to include the least libraries and external dependencies as possible, I am looking to create an agile and relatively lightweight application(from round trips and overall static files weight point of view).
  • Oleg Belousov
    Oleg Belousov almost 11 years
    Also, my API requires me to post the file as multi-part along with a bunch of other formData, this is the reason why I tried the solution from the 'code like a poem blog'
  • jvandemo
    jvandemo almost 11 years
    I created a working version of your plnkr at plnkr.co/edit/VAlEaR?p=preview. If you open the console you will notice that the upload is triggered when the button is clicked (but doesn't succeed as there is no server to send it to). If you need additional help, just let me know...
  • Oleg Belousov
    Oleg Belousov almost 11 years
    Thank you sir, the one last thing that I need is to be able to upload from data(text fields) along with the file since the new version of my API has one endpoint for attachment and other textual data. I also took the liberty of subscribing to your blog, looks very interesting!
  • jvandemo
    jvandemo almost 11 years
    I added additional input fields to the form in the plnkr: plnkr.co/edit/VAlEaR?p=preview. You can add any data you like (input, select, etc). It will be sent as a POST param along with the file uploads. Thanks for subscribing to my blog!
  • Oleg Belousov
    Oleg Belousov almost 11 years
    Thanks for all of the kind help and specific explanations & examples, although you're answer doesn't solve my original problem precisely, it is most definitely correct and working, so I marked you answer as the correct one for others to learn from it. Do you actively participate on any IRC channel perhaps, so I'll be able to use your advice if I'll encounter any problems with re-factoring my code?
  • Oleg Belousov
    Oleg Belousov almost 11 years
    BTW, I need CORS support, can I set an external API link as my target at the form?, provided I'll add withCredentials: true to the xhrFields at the bluimp config
  • Oleg Belousov
    Oleg Belousov almost 11 years
    It is weird, but for me the upload doesn't fire for some reason
  • jvandemo
    jvandemo almost 11 years
    Yes, if you need CORS support, then you'll have to enable the withCredentials option. Also, the server side will have to add the correct headers to accept your request. You can find the exact headers in my answer on stackoverflow.com/questions/18310394/…. The example is about Node.js but the headers are the same with any server side technology. Are you using the browser devtools to check if the upload fires? You should see the browser trying to POST to the current url (which will fail due to being on plnkr).
  • Oleg Belousov
    Oleg Belousov almost 11 years
    It appears that you have included the AngularJS library twice, once the 1.0.5 version, and once the 1.0.7. I took the liberty to fix that for you
  • Oleg Belousov
    Oleg Belousov almost 11 years
    It is, and with cores support, the only problem is that the API calls the file field 'attachment' and bluimp calls it 'files[]' which kind of screws me up, since my friend who does the backend cannot change it right now because he is out of town without his computer. Any easy way to change the name of the file field in the request headers? Also is there any easy way to $watch the status of the upload, or at least get a success callback function within the controller in order to redirect the user upon success. Sorry for all of the dumb questions and thanks again for the help!
  • jvandemo
    jvandemo almost 11 years
    Blueimp names it files[] because the example is aimed at a PHP backend that can accept multiple file uploads at the same time. You can rename it to attachment and disable multiple uploads in the options. No need to change the headers. As for the callback I will add extra example code to my original answer...
  • Oleg Belousov
    Oleg Belousov almost 11 years
    Renaming the field name to 'attachment' instead of files[] break the code for some reason, I suspect that the js of bluimp refers to this field as $("name['files[]']") or something
  • Oleg Belousov
    Oleg Belousov almost 11 years
    Also, I was looking for a way to use the bluimp basic plugin along with Angular JS, but found no information on that topic, are you familiar with any blog post or article on this topic?
  • jvandemo
    jvandemo almost 11 years
    Blueimp will use files[] as the default input name. If you change it in the form, you will also have to pass it as an option (I believe it is called fileInput but it is best to check the source/docs of the version you are using). As for the basic version, I don't have any experience with that I'm affraid...
  • Oleg Belousov
    Oleg Belousov almost 11 years
    Checked the docs, it is indeed fileInput, the irony is that the source is documented better than the project it self. I ended up changing the jquery.fileupload.js file, but i believe that those options can also be passed as $Scope.options. NO I only need to make some visual enhancements such as displaying the selected file name, and a progress bar perhaps
  • jvandemo
    jvandemo almost 11 years
    Awesome, glad you finally got it working. I would highly recommend not to change the jquery.fileupload.js but rather use the options to pass in the file input name to allow for future maintainability when upgrading to a newer version.
  • Oleg Belousov
    Oleg Belousov almost 11 years
    Agh, now I cannot display the selected file and cannot show the progress bar and the pretty UI options :(
  • merveotesi
    merveotesi over 10 years
    Hi, can you look at the question: stackoverflow.com/questions/21047204/…
  • revolutionNET
    revolutionNET over 9 years
    Nice answer, I want to preview the image before upload with 100% wdth and height, what should I do?
  • Shivendra
    Shivendra about 8 years
    Somebody there? i wanted to ask that when fileuploadstop event is successfully fired, how can I see the data that is returned back. I passed the data parameter in the function but it is not giving much information like it used to give in the simple jquery version of the blueimp library.