Angularjs how to upload multipart form data and a file?

£可爱£侵袭症+ 提交于 2019-11-26 07:22:25

问题


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?


回答1:


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>



回答2:


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.




回答3:


It is more efficient to send the files 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:

Doing Multiple $http.post Requests Directly from a FileList

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

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.


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

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

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="fileList" multiple>
    
    <h2>Files</h2>
    <div ng-repeat="file in fileList">
      {{file.name}}
    </div>
  </body>



回答4:


You can check out this method for sending image and form data altogether

<div class="form-group ml-5 mt-4" ng-app="myApp" ng-controller="myCtrl">
                    <label for="image_name">Image Name:</label>
                    <input type="text"   placeholder="Image name" ng-model="fileName" class="form-control" required>
                    <br>

                    <br>
                    <input id="file_src" type="file"   accept="image/jpeg" file-input="files"   >
                    <br>
                        {{file_name}}
            <img class="rounded mt-2 mb-2 " id="prvw_img" width="150" height="100" >
                    <hr>
                      <button class="btn btn-info" ng-click="uploadFile()">Upload</button>
                        <br>

                       <div ng-show = "IsVisible" class="alert alert-info w-100 shadow mt-2" role="alert">
              <strong> {{response_msg}} </strong>
            </div>
                            <div class="alert alert-danger " id="filealert"> <strong> File Size should be less than 4 MB </strong></div>
                    </div>

Angular JS Code

    var app = angular.module("myApp", []);
 app.directive("fileInput", function($parse){
      return{
           link: function($scope, element, attrs){
                element.on("change", function(event){
                     var files = event.target.files;


                     $parse(attrs.fileInput).assign($scope, element[0].files);
                     $scope.$apply();
                });
           }
      }
 });
 app.controller("myCtrl", function($scope, $http){
      $scope.IsVisible = false;
      $scope.uploadFile = function(){
           var form_data = new FormData();
           angular.forEach($scope.files, function(file){
                form_data.append('file', file); //form file
                                form_data.append('file_Name',$scope.fileName); //form text data
           });
           $http.post('upload.php', form_data,
           {
                //'file_Name':$scope.file_name;
                transformRequest: angular.identity,
                headers: {'Content-Type': undefined,'Process-Data': false}
           }).success(function(response){
             $scope.IsVisible = $scope.IsVisible = true;
                      $scope.response_msg=response;
               // alert(response);
               // $scope.select();
           });
      }

 });


来源:https://stackoverflow.com/questions/24443246/angularjs-how-to-upload-multipart-form-data-and-a-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!