AngularJS: How To Implement A Simple File Upload With Multipart Form?


Answer :

A real working solution with no other dependencies than angularjs (tested with v.1.0.6)

html

<input type="file" name="file" onchange="angular.element(this).scope().uploadFile(this.files)"/> 

Angularjs (1.0.6) not support ng-model on "input-file" tags so you have to do it in a "native-way" that pass the all (eventually) selected files from the user.

controller

$scope.uploadFile = function(files) {     var fd = new FormData();     //Take the first selected file     fd.append("file", files[0]);      $http.post(uploadUrl, fd, {         withCredentials: true,         headers: {'Content-Type': undefined },         transformRequest: angular.identity     }).success( ...all right!... ).error( ..damn!... );  }; 

The cool part is the undefined content-type and the transformRequest: angular.identity that give at the $http the ability to choose the right "content-type" and manage the boundary needed when handling multipart data.


You can use the simple/lightweight ng-file-upload directive. It supports drag&drop, file progress and file upload for non-HTML5 browsers with FileAPI flash shim

<div ng-controller="MyCtrl">   <input type="file" ngf-select="onFileSelect($files)" multiple> </div> 

JS:

//inject angular file upload directive. angular.module('myApp', ['ngFileUpload']);  var MyCtrl = [ '$scope', 'Upload', function($scope, Upload) {   $scope.onFileSelect = function($files) {   Upload.upload({     url: 'my/upload/url',     file: $files,               }).progress(function(e) {   }).then(function(data, status, headers, config) {     // file is uploaded successfully     console.log(data);   });   }]; 

It is more efficient to send a file directly.

The base64 encoding of Content-Type: multipart/form-data adds an extra 33% overhead. If the server supports it, it is more efficient to send the files directly:

$scope.upload = function(url, file) {     var config = { headers: { 'Content-Type': undefined },                    transformResponse: angular.identity                  };     return $http.post(url, file, config); }; 

When sending a POST with a File object, it is important to set 'Content-Type': undefined. The XHR send method will then detect the File object and automatically set the content type.

To send multiple files, see Doing Multiple $http.post Requests Directly from a FileList


I figured I should start with input type="file", but then found out that AngularJS can't bind to that..

The <input type=file> element does not by default work with the ng-model directive. It needs a custom directive:

Working Demo of "select-ng-files" Directive that Works with ng-model1

angular.module("app",[]);  angular.module("app").directive("selectNgFiles", function() {   return {     require: "ngModel",     link: function postLink(scope,elem,attrs,ngModel) {       elem.on("change", function(e) {         var files = elem[0].files;         ngModel.$setViewValue(files);       })     }   } });
<script src="//unpkg.com/angular/angular.js"></script>   <body ng-app="app">     <h1>AngularJS Input `type=file` Demo</h1>          <input type="file" select-ng-files ng-model="fileArray" multiple>          <h2>Files</h2>     <div ng-repeat="file in fileArray">       {{file.name}}     </div>   </body>


$http.post with content type multipart/form-data

If one must send multipart/form-data:

<form role="form" enctype="multipart/form-data" name="myForm">     <input type="text"  ng-model="fdata.UserName">     <input type="text"  ng-model="fdata.FirstName">     <input type="file"  select-ng-files ng-model="filesArray" multiple>     <button type="submit" ng-click="upload()">save</button> </form> 
$scope.upload = function() {     var fd = new FormData();     fd.append("data", angular.toJson($scope.fdata));     for (i=0; i<$scope.filesArray.length; i++) {         fd.append("file"+i, $scope.filesArray[i]);     };      var config = { headers: {'Content-Type': undefined},                    transformRequest: angular.identity                  }     return $http.post(url, fd, config); }; 

When sending a POST with the FormData API, it is important to set 'Content-Type': undefined. The XHR send method will then detect the FormData object and automatically set the content type header to multipart/form-data with the proper boundary.


Comments

Popular posts from this blog

Are Regular VACUUM ANALYZE Still Recommended Under 9.1?

Can Feynman Diagrams Be Used To Represent Any Perturbation Theory?