Uploading local images using AngularJS

This post will show you how to upload local images using Angular and ng-upload. A few notes before we dive into the technical details: the code snippets below were added to my existing code, this was part of a MEAN stack app (Angular, Express/Node, MongoDB). This is recommended for users who have some minimal experience with AngularJS controllers.

Ng-upload will need to be installed: ng-upload

HTML code that allows a user to upload a local image from their computer:

  <h4>Upload on file select</h4>
  <div>
     <button type="file" ngf-select="uploadFiles($file, $invalidFiles)"
        accept="image/*" style="color:black; border-radius: 5px;" ngf-max-height="10000" ngf-max-size="20MB">
        Select File
    </button>
  </div>

Note: The attributes “ngf-max-height” “ngf-max-size” allow you to set limits on image height and size. Once the pic is selected, “ngf-select” calls the function “uploadFiles” with the arguments (the user selected file and a potential invalid file message).



To display the results of the file upload, include the following in your HTML file:

 Uploaded File:
  <div style="font:smaller">{{f.name}} {{errFile.name}} {{errFile.$error}} {{errFile.$errorParam}}
    <span class="progress" ng-show="f.progress >= 0">
      <div style="width:{{f.progress}}%"
      ng-bind="f.progress + '%'"></div>
    </span>
  </div>
  <br><br>

  <!-- Display the the image returned from the server -->
  <img ng-src="data:image/jpg;base64,{{image}}">
  <br>


Angular controller code for the above HTML:

.controller('someControllerName', ['$scope', 'Upload', '$timeout', function($scope, Upload, $timeout) {

// Use to convert an arraybuffer to a base 64 string 

function _arrayBufferToBase64( buffer ) {
    var binary = '';
    var bytes = new Uint8Array( buffer );
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
    }
  return window.btoa( binary );
}

// Function that calls ng-upload's Upload function
$scope.uploadFiles = function(file, errFiles) {
  $scope.f = file;
  $scope.errFile = errFiles && errFiles[0];
   if (file) {
      file.upload = Upload.upload({
        url: '/images',
        data: { file: file },
      });
     file.upload.then(function(response) {
  
        // response is an array buffer that needs to be converted to a base64 encoded string in
        // order to used by the img element ex:<img ng-src=“data:image/jpg;base64,">

        var dataNow64bit = _arrayBufferToBase64(response.data.img.data.data);

       $scope.image = dataNow64bit;

        $timeout(function() {
          file.result = response.data;
        });
      },
  
      function(response) {
        if (response.status > 0)
          $scope.errorMsg = response.status + ': ' + response.data;
      },
  
      function(evt) {
        file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
      });
    }
  };

}

References:
http://jsfiddle.net/danialfarid/0mz6ff9o/135
http://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string

Written on February 9, 2016