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

1

5

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>
Tractate answered 26/8, 2013 at 13:38 Comment(0)
C
13

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!

Corrincorrina answered 2/9, 2013 at 20:21 Comment(24)
Is there anyway to integrate this submit method in my current code?Tractate
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 & helpTractate
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!Corrincorrina
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).Tractate
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'Tractate
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...Corrincorrina
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!Tractate
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!Corrincorrina
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?Tractate
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 configTractate
It is weird, but for me the upload doesn't fire for some reasonTractate
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 #18310894. 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).Corrincorrina
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 youTractate
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!Tractate
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...Corrincorrina
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 somethingTractate
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?Tractate
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...Corrincorrina
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 perhapsTractate
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.Corrincorrina
Agh, now I cannot display the selected file and cannot show the progress bar and the pretty UI options :(Tractate
Hi, can you look at the question: #21047704Manned
Nice answer, I want to preview the image before upload with 100% wdth and height, what should I do?Nonagenarian
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.Pignut

© 2022 - 2024 — McMap. All rights reserved.