AngularJS: comment implémenter un téléchargement de fichier simple avec un formulaire multipart?

je veux faire un poteau de forme simple multipart D'AngularJS à un noeud.js serveur, le formulaire doit contenir un objet JSON dans une partie et une image à l'autre partie, (Je suis actuellement en détachement seulement l'objet JSON avec $ressource)

j'ai pensé que je devrais commencer avec input type=" file", mais j'ai découvert que AngularJS ne peut pas se lier à ça..

tous les exemples que je peux trouver sont pour wraping plugins jQuery pour drag & drop. Je veux un téléchargement simple de un fichier.

Je suis nouveau à AngularJS et ne me sens pas à l'aise du tout avec l'écriture de mes propres directives.

136
demandé sur georgeawg 2012-12-20 03:35:57

8 réponses

une véritable solution de travail sans autres dépendances qu'angularjs (testé avec v. 1.0.6)

html

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

Angularjs (1.0.6) ne supporte pas ng-model sur les étiquettes "input-file" de sorte que vous devez le faire dans un "native-way" qui passent tous (éventuellement) les fichiers sélectionnés de l'utilisateur.

contrôleur

$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!... );

};

le la partie cool est le type de contenu Non défini et la transformRequest : angulaire.identité qui donnent à $http la possibilité de choisir le bon" content-type " et gérer la frontière nécessaire lors du traitement de données multipart.

175
répondu Fabio Bonfante 2014-04-24 17:25:02

vous pouvez utiliser la directive simple/légère ng-file-upload . Il prend en charge la traînée et la goutte, la progression de fichier et le téléchargement de fichier pour les navigateurs non-HTML5 avec 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);
  }); 

}];
40
répondu danial 2016-12-04 18:50:23

je viens d'avoir ce problème. Il y a donc quelques approches. Le premier est que les nouveaux navigateurs prennent en charge le

var formData = new FormData();

suivez ce lien vers un blogue avec des informations sur comment le support est limité aux navigateurs modernes, mais sinon il résout totalement cette question.

sinon vous pouvez poster le formulaire sur une iframe en utilisant l'attribut cible. Lorsque vous postez le formulaire soyez sûr de définir la cible à une iframe avec sa propriété display la valeur none. La cible est le nom de l'iframe. (Juste pour que vous le savez.)

j'espère que cette aide

5
répondu Edgar Martinez 2013-02-07 16:26:38

Il est plus efficace d'envoyer un fichier directement.

le base64 encodant de Content-Type: multipart/form-data ajoute un supplément de 33% de frais généraux. Si le serveur le supporte, il est plus efficace d'envoyer les fichiers directement:

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

lors de l'envoi d'un message avec un File object , il est important de définir 'Content-Type': undefined . Le XHR méthode d'envoi détecter les "1519240920 Fichier" objet et automatiquement défini le type de contenu.

pour envoyer plusieurs fichiers, voir faire plusieurs $http.post requêtes directement à partir d'une liste de fichiers


j'ai pensé que je devrais commencer avec input type=" file", mais j'ai découvert que AngularJS ne peut pas se lier à cela..

l'élément <input type=file> ne travail par défaut avec la ng-model directive . Il a besoin d'une directive personnalisée :

démo de travail de la Directive" select-ng-files " qui fonctionne avec ng-model 1

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 avec le type de contenu multipart/form-data

si on doit envoyer 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);
};

lors de l'envoi d'un message avec FormData API , il est important de définir 'Content-Type': undefined . La méthode XHR send détectera alors l'objet FormData et positionnera automatiquement l'en-tête content type à multipart/form-data avec la proper boundary .

5
répondu georgeawg 2018-08-29 02:49:27

je sais qu'il s'agit d'une entrée tardive, mais j'ai créé une simple directive de téléchargement. Que vous pouvez travailler en un rien de temps!

<input type="file" multiple ng-simple-upload web-api-url="/api/post" callback-fn="myCallback" />

ng-simple-upload plus sur Github avec un exemple utilisant L'API Web.

2
répondu shammelburg 2016-02-16 11:30:20

vous pouvez télécharger via $resource en assignant des données à l'attribut params de la ressource actions like so:

$scope.uploadFile = function(files) {
    var fdata = new FormData();
    fdata.append("file", files[0]);

    $resource('api/post/:id', { id: "@id" }, {
        postWithFile: {
            method: "POST",
            data: fdata,
            transformRequest: angular.identity,
            headers: { 'Content-Type': undefined }
        }
    }).postWithFile(fdata).$promise.then(function(response){
         //successful 
    },function(error){
        //error
    });
};
1
répondu Digitlimit 2018-09-21 11:43:47

je viens d'écrire une directive simple (à partir d'une directive existante, bien sûr) pour un simple uploader à AngularJs.

(le plugin uploader exact de jQuery est https://github.com/blueimp/jQuery-File-Upload )

Un Simple Uploader en utilisant AngularJs (avec de la SCRO mise en Œuvre)

(bien que le côté serveur soit pour PHP, vous pouvez simplement changer le noeud it aussi)

0
répondu sk8terboi87 ツ 2017-05-23 12:26:36

je voudrais ajouter une alternative. En utilisant le fichier angulaire-upload. Vous pouvez trouver une explication:

vous pouvez trouver une explication détaillée ici: https://github.com/nervgh/angular-file-upload un exemple: https://github.com/nervgh/angular-file-upload/tree/master/examples/simple

0
répondu Leo Much 2017-08-07 07:15:27