Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angularjs how to upload multipart form data and a file?

I'm a beginner to angular.js but I have a good grasp of the basics.

What I am looking to do is upload a file and some form data as multipart form data. I read that this isn't a feature of angular, however 3rd party libraries can get this done. I've cloned angular-file-upload via git, however I am still unable to post a simple form and a file.

Can someone please provide an example, html and js of how to do this?

like image 589
CodingIsAwesome Avatar asked Jun 27 '14 02:06

CodingIsAwesome


People also ask

How do you send a file using multipart form data?

Follow this rules when creating a multipart form: Specify enctype="multipart/form-data" attribute on a form tag. Add a name attribute to a single input type="file" tag. DO NOT add a name attribute to any other input, select or textarea tags.

What is a multipart file upload?

Multipart upload allows you to upload a single object as a set of parts. Each part is a contiguous portion of the object's data. You can upload these object parts independently and in any order. If transmission of any part fails, you can retransmit that part without affecting other parts.

What is FormData in Angular JS?

The FormData. entries() method provides an iterator for going through all key/value pairs of the instance. The FormData. get() method Returns the first value associated with a given key from within a FormData object.


2 Answers

First of all

  1. You don't need any special changes in the structure. I mean: html input tags.

<input accept="image/*" name="file" ng-value="fileToUpload"         value="{{fileToUpload}}" file-model="fileToUpload"         set-file-data="fileToUpload = value;"          type="file" id="my_file" />

1.2 create own directive,

.directive("fileModel",function() {  	return {  		restrict: 'EA',  		scope: {  			setFileData: "&"  		},  		link: function(scope, ele, attrs) {  			ele.on('change', function() {  				scope.$apply(function() {  					var val = ele[0].files[0];  					scope.setFileData({ value: val });  				});  			});  		}  	}  })
  1. In module with $httpProvider add dependency like ( Accept, Content-Type etc) with multipart/form-data. (Suggestion would be, accept response in json format) For e.g:

$httpProvider.defaults.headers.post['Accept'] = 'application/json, text/javascript'; $httpProvider.defaults.headers.post['Content-Type'] = 'multipart/form-data; charset=utf-8';

  1. Then create separate function in controller to handle form submit call. like for e.g below code:

  2. In service function handle "responseType" param purposely so that server should not throw "byteerror".

  3. transformRequest, to modify request format with attached identity.

  4. withCredentials : false, for HTTP authentication information.

in controller:      // code this accordingly, so that your file object     // will be picked up in service call below.    fileUpload.uploadFileToUrl(file);       in service:      .service('fileUpload', ['$http', 'ajaxService',      function($http, ajaxService) {          this.uploadFileToUrl = function(data) {          var data = {}; //file object             var fd = new FormData();          fd.append('file', data.file);            $http.post("endpoint server path to whom sending file", fd, {              withCredentials: false,              headers: {                'Content-Type': undefined              },              transformRequest: angular.identity,              params: {                fd              },              responseType: "arraybuffer"            })            .then(function(response) {              var data = response.data;              var status = response.status;              console.log(data);                if (status == 200 || status == 202) //do whatever in success              else // handle error in  else if needed             })            .catch(function(error) {              console.log(error.status);                // handle else calls            });        }      }    }])
<script src="//unpkg.com/angular/angular.js"></script>
like image 58
Prasad Shinde Avatar answered Sep 27 '22 22:09

Prasad Shinde


This is pretty must just a copy of that projects demo page and shows uploading a single file on form submit with upload progress.

(function (angular) { 'use strict';  angular.module('uploadModule', [])     .controller('uploadCtrl', [         '$scope',         '$upload',         function ($scope, $upload) {             $scope.model = {};             $scope.selectedFile = [];             $scope.uploadProgress = 0;              $scope.uploadFile = function () {                 var file = $scope.selectedFile[0];                 $scope.upload = $upload.upload({                     url: 'api/upload',                     method: 'POST',                     data: angular.toJson($scope.model),                     file: file                 }).progress(function (evt) {                     $scope.uploadProgress = parseInt(100.0 * evt.loaded / evt.total, 10);                 }).success(function (data) {                     //do something                 });             };              $scope.onFileSelect = function ($files) {                 $scope.uploadProgress = 0;                 $scope.selectedFile = $files;             };         }     ])     .directive('progressBar', [         function () {             return {                 link: function ($scope, el, attrs) {                     $scope.$watch(attrs.progressBar, function (newValue) {                         el.css('width', newValue.toString() + '%');                     });                 }             };         }     ]);  }(angular)); 

HTML

<form ng-submit="uploadFile()">    <div class="row">          <div class="col-md-12">                   <input type="text" ng-model="model.fileDescription" />                   <input type="number" ng-model="model.rating" />                   <input type="checkbox" ng-model="model.isAGoodFile" />                   <input type="file" ng-file-select="onFileSelect($files)">                   <div class="progress" style="margin-top: 20px;">                     <div class="progress-bar" progress-bar="uploadProgress" role="progressbar">                       <span ng-bind="uploadProgress"></span>                       <span>%</span>                     </div>                   </div>                    <button button type="submit" class="btn btn-default btn-lg">                     <i class="fa fa-cloud-upload"></i>                     &nbsp;                     <span>Upload File</span>                   </button>                 </div>               </div>             </form> 

EDIT: Added passing a model up to the server in the file post.

The form data in the input elements would be sent in the data property of the post and be available as normal form values.

like image 34
Jon Avatar answered Sep 27 '22 22:09

Jon