Search code examples
javascriptphpangularjsng-file-upload

Upload file asynchronously with Angular, ng-file-upload using a RESTful API


I have a form and a few of that form fields are file uploads. This is what I have:

  1. User fills the form up
  2. User selects the files to submit
  3. User presses submit

Now, this is what I want to do:

  1. Post the form to server, getting back an ID
  2. Post file one to server myresource/ID/fileone
  3. Post file two to server myresource/ID/filetwo ...

¿How can I perform this files upload programatically? (I'm using angular promises, so no problem with sequential requests...)

Here is my code:

$scope.upload = function (files, url) {
      if (files && files.length) {
        for (var i = 0; i < files.length; i++) {
          var file = files[i];
          Upload.upload({
            url: 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: ' + data);
          });
        }
      }
    };

My html:

<input type="file" class="btn btn-danger" ng-file-select ng-model="files" ng-multiple="multiple"> Doit!

<input class="btn btn-danger" ng-file-select ng-model="files" ng-multiple="multiple">Doit too!

Solution

  • Ok, so I finally got this.

    I did this:

    1. Select file and store file in ng-model
    2. Validate some stuff
    3. Submit main model (The one owning the files I want to upload)
    4. Upload file to endpoints /api/myentity/{id}/resumee, /api/myentity/{id}/dni and /api/myentity/{id}/picture. Where {id} is the id of the entity I just created in the previous step.

    So the trick here is to execute two requests, one to create the entity and retrieve the id, the second, to just upload the file.

    The code looks like this:

    // This is called every time the user selects a file
    $scope.selectedFile = function (files, doc) {
          if (doc === 'resumee') $scope.documents.resumee = files.pop();
          else if (doc === 'dni') $scope.documents.dni = files.pop();
          else if (doc === 'picture') $scope.documents.picture = files.pop();
    };
    
    // This is called when the user submits the form
    $scope.upload = function (docname, url) {
    
          var file = $scope.stepThree.documents[docname];
    
          return Upload.upload({
            url: url,
            method: 'POST',
            headers: {'Content-Type': file.type},
            fileFormDataName: docname,
            data: file,
            file: file
          }).progress(function (evt) {
            var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
            console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name);
          });
        };
    

    And finally, the markup is this:

    <div class="form-horizontal">
            <div class="form-group">
              <div class="col-sm-2">
                <label> Resumen Curricular </label>
              </div>
              <div class="col-sm-2">
                <button class="btn btn-danger" ngf-select ngf-change="selectFile($files, 'resumee')"> Seleccione</button>
                <p>{{stepThree.documents.resumee.name}}</p>
              </div>
            </div>
     </div>
    

    Since no one commented on this approach/technique, I'll take this as the best way in the world to work with file uploads, angular and a REST API.