Angular.js: prise en charge de la liaison input[type=file]

Créé le 18 sept. 2012  ·  145Commentaires  ·  Source: angular/angular.js

salut en essayant de faire un simple téléchargement de fichier :) mais l'entrée de type=file ne semble pas se lier j'ai essayé hg-model-instant mais n'obtient rien, même mis à niveau vers 1.0.2 et rien

forms moderate not core feature

Commentaire le plus utile

Cette solution dépend du lecteur de fichiers mis en œuvre :

...
.directive('file', function() {
    return {
        restrict: 'E',
        template: '<input type="file" />',
        replace: true,
        require: 'ngModel',
        link: function(scope, element, attr, ctrl) {
            var listener = function() {
                scope.$apply(function() {
                    attr.multiple ? ctrl.$setViewValue(element[0].files) : ctrl.$setViewValue(element[0].files[0]);
                });
            }
            element.bind('change', listener);
        }
    }
});

<file name="image" ng-model="inputFile" accept="image/png,image/jpg,image/jpeg" />

Vous devez ensuite faire quelques trucs xhr vous-même, mais je pense que cela est en dehors de la liaison de l'interface graphique et de la logique de traitement.

et si vous manquez d'imagination :

var file = $scope.inputFile;
$http.put('http://localhost:5984/demo/d06917e8d1fae1ae162ea7773c003f0b/' + file.name + '?rev=4-c10029f35a5c5ed9bd8cc31bf8589d3c', file, { headers: { 'Content-Type' : file.type } });

Cela fonctionne à cause de xhr2 (http://www.html5rocks.com/en/tutorials/file/xhr2) et veuillez excuser le long exemple d'URL de téléchargement, c'est un point de terminaison de document couchdb (pièce jointe).

Tous les 145 commentaires

Il n'y a pas de liaison par défaut fournie par angular à input type=file.

Mais alors, l'entrée de fichier n'est réelle que pour javascript, le seul avantage qu'une telle liaison pourrait aider est d'effacer l'entrée de fichier. (Angular ne fournit pas non plus de prise en charge du cadre pour le téléchargement ajax du fichier en ce moment, je crois)

@coli : ce n'est pas toute la vérité.

Il serait logique de pouvoir intercepter l'événement onchange sur input[file].

Sur https://github.com/lgersman/jquery.orangevolt-ampere, nous avons exactement ce scénario : les téléchargements de fichiers via XMLHTTPRequest V2.
Par conséquent, nous avons implémenté notre propre directive pour intercepter les événements de modification input[file] pour que les téléchargements de fichiers soient effectués sans recharger la page.

J'adorerais voir cette fonctionnalité dans angularjs !

Y a-t-il eu des progrès dans la liaison à une entrée de type fichier ? J'ai cherché une solution et je n'arrive pas à en trouver une qui fonctionne...

ma solution était juste Ajax au lieu de request ou http.post

Envoyé depuis mon iPad

Le 1er mars 2013 à 19h16, "jgoldber" < [email protected] [email protected] > a écrit :

Y a-t-il eu des progrès dans la liaison à une entrée de type fichier ? J'ai cherché une solution et je n'arrive pas à en trouver.

-
Répondez directement à cet e-mail ou consultez-le sur Gi tHubhttps://github.com/angular/angular.js/issues/1375#issuecomment -14321221.

Meilleure solution que j'ai trouvée : http://jsfiddle.net/marcenuc/ADukg/49/. Merci de partager si vous trouvez une meilleure solution.

Ouais, ça a vraiment besoin d'être examiné ; pouvoir sélectionner et télécharger un fichier est assez crucial pour la plupart des applications Web, donc la prise en charge de cette entrée est une fonctionnalité manquante assez évidente.

Cogner. Cela doit être ajouté à un jalon.

Un autre cri à l'appui de cela.

Le fichier ng-model pourrait définir la valeur d'un fichier à partir de l'API de fichier HTML5, il existe des polyfills Flash et Silverlight pour IE8/IE9

Oui, définissez la valeur sur le fichier ou sur l'élément d'entrée (contenant une référence au fichier)

Cette solution dépend du lecteur de fichiers mis en œuvre :

...
.directive('file', function() {
    return {
        restrict: 'E',
        template: '<input type="file" />',
        replace: true,
        require: 'ngModel',
        link: function(scope, element, attr, ctrl) {
            var listener = function() {
                scope.$apply(function() {
                    attr.multiple ? ctrl.$setViewValue(element[0].files) : ctrl.$setViewValue(element[0].files[0]);
                });
            }
            element.bind('change', listener);
        }
    }
});

<file name="image" ng-model="inputFile" accept="image/png,image/jpg,image/jpeg" />

Vous devez ensuite faire quelques trucs xhr vous-même, mais je pense que cela est en dehors de la liaison de l'interface graphique et de la logique de traitement.

et si vous manquez d'imagination :

var file = $scope.inputFile;
$http.put('http://localhost:5984/demo/d06917e8d1fae1ae162ea7773c003f0b/' + file.name + '?rev=4-c10029f35a5c5ed9bd8cc31bf8589d3c', file, { headers: { 'Content-Type' : file.type } });

Cela fonctionne à cause de xhr2 (http://www.html5rocks.com/en/tutorials/file/xhr2) et veuillez excuser le long exemple d'URL de téléchargement, c'est un point de terminaison de document couchdb (pièce jointe).

Il est possible de faire fonctionner cela dans IE8/9 en combinant ce FileReader Polyfill basé sur flash https://github.com/Jahdrien/FileReader et ce polyfill pur js FormData qui repose sur FileReader https://github.com/francois2metz/ html5-formdata. _update_ Moxie est un meilleur polyfill

Ma solution était assez sommaire, au moins aussi sommaire que le jsfiddle ci-dessus où le prototype de contrôleur est bricolé...

Dans le contrôleur :

    $scope.updateImage = '(' + function () {
      alert('moo');
    }.toString() + ')();';

Stringifier mon rappel onchange souhaité et l'envelopper dans une fermeture.

   <input type="file" name="image" onchange="{{updateImage}}" ng-model="image">

Insérez-le dans le DOM en utilisant Angular

Pas vraiment joli mais cela fonctionne dans Webkit. Je n'ai fait aucun test cross-navigateur.

Je suis sur 1.0.5 et c'est toujours cassé. Nous avons utilisé l'exemple de Jgoldber et l'avons légèrement modifié :
http://jsfiddle.net/ADukg/2589/

Cet exemple ne fonctionnera que pour un seul contrôleur, donc si vous avez plusieurs contrôleurs, chacun avec des entrées de fichier, vous devrez apporter quelques modifications.

Je ne l'ai pas encore testé sur IE, mais je suppose (connaissant IE) que cela ne fonctionnera pas.

En supposant que vous souhaitiez simplement appeler une fonction dans votre portée qui prend l'élément d'entrée comme argument, c'est assez simple à implémenter dans une directive :

http://jsfiddle.net/neilsarkar/vQzKJ/

(modifié à partir du jsfiddle ci-dessus, merci @programmist)

'use strict';

function filesModelDirective(){
  return {
    controller: function($parse, $element, $attrs, $scope){
      var exp = $parse($attrs.filesModel);

      $element.on('change', function(){
        exp.assign($scope, this.files);
        $scope.$apply();
      });
    }
  };
}

configuration:

angular.module(...).directive('filesModel', filesModelDirective)

usage:

<input type="file" files-model="someObject.files" multiple>

Veuillez corriger cela rapidement.

Toujours des problèmes.. dans certaines versions, cela fonctionne mais n'est de toute façon pas pris en charge

Depuis la version 1.5.0, $digest doit être appelé si vous utilisez la solution de contournement onchange :

<input type="file" onchange="angular.element(this).scope().myController.uploadFile(this.files[0]); angular.element(this).scope().$digest();">

+1 pour un meilleur support sur le ng-change et l'entrée/fichier. Cas d'utilisation : en tant que téléchargeur d'une image, j'aimerais pouvoir modifier cette image (redimensionner et recadrer) avant de la télécharger pour un affichage optimal. Implémentation : accédez à l'image (en utilisant input/file) et lors de l'événement onchange, déplacez le fichier vers le canevas et modifiez-le avec fabricjs. Je ne peux pas penser à une mise en œuvre sans changement.

cztomsik - Je suis sur 1.0.7 et je ne parviens pas à faire fonctionner votre solution - la fonction scope (this) se résout bien, mais le contrôleur est introuvable, la fonction uploadFile est répertoriée comme membre de la portée (this).

Je déconne, j'ai une légère modification sur la technique, qui semble fonctionner pour moi (je ne sais toujours pas pourquoi j'ai eu le :

< input type="file" name="file" ng-model="file" onchange="invokeUploadFile(this)"/ >

var invokeUploadFile = function(that) {
angular.element(that).scope().uploadFile(that)
angular.element(that).scope().$digest();
}

Pourriez-vous fournir jsfiddle/plunker ?
THX


    1. 2013 v 18:17, tb01923 [email protected] :

+1 pour un meilleur support sur le ng-change et l'entrée/fichier. Cas d'utilisation : en tant que téléchargeur d'une image, j'aimerais pouvoir modifier cette image (redimensionner et recadrer) avant de la télécharger pour un affichage optimal. Implémentation : accédez à l'image (en utilisant input/file) et lors de l'événement onchange, déplacez le fichier vers le canevas et modifiez-le avec fabricjs. Je ne peux pas penser à une mise en œuvre sans changement.

cztomsik - Je suis sur 1.0.7 et je n'arrive pas à faire fonctionner votre solution - la fonction scope(this) se résout correctement, mais le contrôleur est introuvable, la fonction uploadFile est répertoriée comme membre de l'objet scope(this) mais quand je retirer le contrôleur que je reçois

Uncaught ReferenceError: uploadFile n'est pas défini blah.js:15
$scope.uploadFile blah.js:15
invokeScope blah.js:4
sur le changement

-
Répondez directement à cet e-mail ou consultez-le sur GitHub.

+1. Vous en avez besoin pour lancer un téléchargement de fichier HTML5 lorsqu'un utilisateur sélectionne un fichier. C'est facile à contourner, mais je m'attendrais à ce que cela fonctionne.

+1. s'il vous plaît implémenter, ne pas l'implémenter n'est absolument pas intuitif.

+1

+1

Allez les gars... ça fait plus d'un an et angular 1.2.0 n'a toujours pas de liaisons de fichiers d'entrée... Je ne comprends pas pourquoi la fonctionnalité n'est pas ajoutée ? Il y a eu quelques bonnes solutions pour la mise en œuvre. Je voudrais une réponse angulaire d'un membre de l'équipe sur le problème s'il vous plaît.

Juste pour citer l'une des meilleures solutions (je sais que c'est une liaison de données à sens unique mais c'est toujours mieux que rien, la validation et la mise à jour du modèle fonctionnent même dans IE7) :

Définition

  /**
   * <strong i="8">@ngdoc</strong> inputType
   * <strong i="9">@name</strong> angular.module.ng.$compileProvider.directive.input.file
   *
   * <strong i="10">@description</strong>
   * HTML file input field.
   *
   * <strong i="11">@param</strong> {string} ngModel Assignable angular expression to data-bind to.
   * <strong i="12">@param</strong> {string} multiple Allows multiple files selection.
   * <strong i="13">@param</strong> {string=} name Property name of the form under which the 
                                control is published.
   *
   * <strong i="14">@example</strong>
      <doc:example>
        <doc:source>
         <script>
           function Ctrl($scope) {
           }
         </script>
         <form name="myForm" ng-controller="Ctrl">
           file: <input type="file" ng-model="file"> single file selection.<br/>
           files: <input type="file" ng-model="files" multiple> multi-file selection.<br/>
           <tt>file.name = {{file.name}}</tt><br/>
           <tt>files.length = {{files.length}}</tt><br/>
          </form>
        </doc:source>
        <doc:scenario>
          it('should change state', function() {
            expect(binding('file.name')).toBeUndefined();

            input('file').select('a file name');
            expect(binding('file.name')).toEqual('a file name');
          });
        </doc:scenario>
      </doc:example>
   */
  'file': fileInputType,

Fonction

function fileInputType(scope, element, attr, ctrl) {
  element.bind('change', function() {
    scope.$apply(function() {
      var files = element[0].files,
          isValid = true;

      if (msie < 10) {
        files = [element[0].value];
      }

      if (attr.accept) {
        var i, j, acceptType, fileType,
            types = map(attr.accept.split(','), function(t) { return trim(t).split('/'); });
        for (i = 0; i < files.length && isValid; ++i) {
          fileType = files[i].type.split('/');
          isValid = false;
          for (j = 0; j < types.length && !isValid; ++j) {
            acceptType = types[j];
            isValid = acceptType[0] === fileType[0] && (acceptType[1] === '*' || acceptType[1] === fileType[1]);
          }
        }
      }
      ctrl.$setValidity('file', isValid);

      var viewValue;
      if (isValid) viewValue = attr.multiple ? files : files[0];
      ctrl.$setViewValue(viewValue);
    });
  });
}

+1

+1

@ntrp Pourquoi ne faites-vous pas de relations publiques avec ce changement ?

Ce changement doit être élaboré un peu et testé, je n'ai pas le temps pour le moment de le faire.

+1

+1

-1 : face de troll :

Je plaisante +1

+1

+1

+1

+1

+1

input[type=file] n'est pas vraiment une liaison bidirectionnelle, à moins que nous n'utilisions explicitement l'API File, qui n'est pas disponible sur tous les navigateurs cibles. L'ajouter à ng-model n'a pas beaucoup de sens, mais il existe de nombreux plugins prenant en charge certaines variantes de cette fonctionnalité. Ne sommes-nous pas d'accord pour déléguer cela aux plugins pendant un certain temps ?

http://caniuse.com/fileapi

@caitp Correct , mais il est logique de pouvoir se lier à l'événement de changement, via ng-change, ce qui ne fonctionne pas.

Une autre chose qui ne fonctionne pas est la validation de formulaire. Je pense que la prise en charge des fichiers devrait être implémentée pour les nouveaux navigateurs avec un repli de liaison de données à sens unique pour les anciens. Si cette solution n'est pas viable alors, à mon avis, il devrait être clairement indiqué sur le wiki pourquoi la fonctionnalité n'est pas implémentée et comment résoudre les problèmes que ce manque de support provoque. Je me souviens avoir perdu beaucoup de temps avant de résoudre mes besoins en fichiers d'entrée lorsque je les ai utilisés pour la première fois.

Le fait est que les noms de fichiers ne sont pas liés à un modèle, et cela n'aurait pas vraiment de sens de les lier à un modèle. Chaque propriété de l'interface File est en lecture seule et l'interface FileList n'est qu'une collection de Files. Il n'y a pas de capacité de liaison bidirectionnelle, il n'y a donc aucune raison réelle d'utiliser ng-model pour ceux-ci en premier lieu. Il est assez simple de se lier à l'événement change place, et vous pouvez facilement écrire une directive pour ajouter cette fonctionnalité afin que vous puissiez l'utiliser de manière déclarative si vous en avez besoin.

Mais en quoi cela a-t-il du sens d'en faire une partie du modèle ng alors qu'il n'a pas la capacité de suivre le comportement du modèle ng ?

Il n'y a aucune raison de ne pas créer une interface personnalisée pour les fichiers, et angular peut le faire à un moment donné, mais cela n'a pas vraiment de sens avec ng-model à mon avis. Je ne sais pas ce que les autres développeurs en pensent, ils peuvent être d'accord ou pas. Mais de mon point de vue, une directive distincte aurait plus de sens, car input[type=file] ne rentre tout simplement pas dans ng-model

  • Rien sur la valeur d'une entrée de fichier n'est accessible en écriture à partir d'un contexte de script
  • Nous n'avons aucun moyen réel d'effectuer la validation ici sans l'API File (qui n'est pas prise en charge par plusieurs navigateurs cibles), le navigateur le fait pour nous, essentiellement. --- à l'exception de la validation ngRequired

La seule chose que nous pourrions vraiment faire pour input[type=file] est $ setViewValue lorsque la valeur change (ce qui n'a pas vraiment de sens), et modifier en quelque sorte ngModel pour ignorer les modifications de la valeur du modèle causées par un changement de script (ou essentiellement désactivez simplement la $watch entièrement). En ce qui concerne la validation, tout ce que nous pouvons vraiment prendre en charge est ng-requis, je veux dire que pouvons-nous faire d'autre là-bas ?

J'aimerais également pouvoir prendre en charge une entrée de fichier avec ngModel, mais je ne vois pas comment cela fonctionnerait, cela ne rentre tout simplement pas dans l'interface ngModel.

Je suis d'accord avec cette affirmation mais, comme je l'ai déjà dit, nous devons insister davantage là-dessus dans le wiki ou en général dans la documentation afin que les développeurs sachent ce qu'ils doivent faire pour obtenir les fonctionnalités dont ils ont besoin.

Les correctifs

L'ajout d'une directive spécifique en angulaire peut-il être une solution?

Je suis d'accord avec la déclaration précédente, mais cela semble au moins un peu étrange qu'un
un cadre comme angulaire n'a pas de moyen clair et propre pour atteindre
cette...
C'était probablement la chose la plus désorientante à laquelle j'ai dû faire face en essayant de
télécharger un fichier...

Ah ok @caitp , j'ai lu il y a quelque temps que la demande d'extraction de wiki n'était pas vraiment évaluée activement, donc je n'ai pas pris la peine de contribuer. Si j'ai du temps libre bientôt, je contribuerai avec plaisir alors :) merci.

Je ne savais pas que la directive ngChange exigeait également la présence de ngModel, ce qui, je suppose, est la raison pour laquelle il y a tant de discussions sur ngModel ici (et c'est pourquoi j'obtiens cette erreur ). Je suis d'accord que la liaison bidirectionnelle sur une entrée[type=fichier] n'a pas de sens.

Mais quelle est la raison exacte pour laquelle ngModel est requis par ngChange ? Dans mon esprit, il est tout à fait logique de pouvoir se lier à l'événement de modification d'un champ input[type=file], par exemple si vous souhaitez soumettre automatiquement le formulaire une fois qu'un fichier est choisi. Dans un tel cas, je ne me soucie pas vraiment de la valeur du champ. Je me soucie seulement que ça change. La meilleure façon que j'ai trouvée de gérer une telle chose est la solution de contournement mentionnée ci-dessus par @cztomsik :

onchange="angular.element(this).scope().fileChangedHandler()"

Et cela ne semble pas vraiment être la meilleure solution.

ng-change , bien qu'il porte le même nom que les autres directives de gestionnaire d'événements, n'est pas en fait un gestionnaire pour l'événement change . Il ajoute simplement un $viewChangeListener au ngModelController, qui se déclenche chaque fois que $setViewValue est appelé.

je suis d'accord c'est un nom malheureux

C'est une dupe de #1236 qui a été clôturée avec ce commentaire : https://github.com/angular/angular.js/issues/1236#issuecomment -29115377

à moins que nous ne voyions une proposition sur la façon d'implémenter cela afin qu'il soit léger, mais fonctionnel et ne nécessite pas de forcer un style ux sur les utilisateurs de framewok, nous l'examinerons. Mais pour le moment, nous pensons que les problèmes de téléchargement de fichiers sont suffisamment complexes pour mériter d'être résolus en tant que module séparé, probablement en dehors du noyau.

+1

@IgorMinar jetez un oeil ici, exemple d'implémentation un peu sale, mais très intéressant : https://github.com/danialfarid/angular-file-upload. @danialfarid fait de grands progrès avec ça.

Vérifiez comment c'est un problème pour tous, plusieurs problèmes ouverts avec plusieurs commentaires. Vous devez nous fournir un module ngUpload : smile:. Vous pouvez peut-être fournir une implémentation html5 et ajouter des exemples d'utilisation avec https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills#file -api à http://docs.angularjs.org/guide /c'est à dire.

Comment pensez-vous résoudre ?

+1

+1

+1

+1

+1

+1

+1

+1

Wow, c'est un peu gênant à ce stade.

+1

Il n'est pas vraiment possible d'avoir des liaisons bidirectionnelles pour les entrées de fichiers, surtout lorsque les navigateurs cibles ne prennent pas tous en charge l' API File (http://caniuse.com/fileapi) --- Mais même quand ils le peuvent, input[type=file] ne rentre pas vraiment dans ça de toute façon. La liaison à 2 voies y est vraiment impossible

Je suis désolé mais c'est plus un problème/une fonctionnalité de sécurité de la plate-forme Web qu'autre chose. Si c'était faisable, ce serait fait

@caitp Je

Quelque chose d'aussi simple qu'un emballage pour cela par exemple serait un début.

Compte tenu de la direction prise par Angular 2.0 (transpilation d'idiomes angulaires uniquement et non ECMA), je ne pense pas que les limitations de la "plate-forme Web" devraient être un problème.

@everyone else : Que fait Ember dans ce cas ?

Edit : suppression de « requis » de la déclaration de transpilation.

_Juste une clarification rapide._ La création d'applications Angular 2.0 ne nécessite pas de langage transpilé ou d'idiomes non ECMA. Vous pouvez très bien utiliser le code ES5 brut. Si vous souhaitez créer la source Angular 2.0, vous devez utiliser traceur pour compiler. Naturellement, vous pouvez utiliser traceur pour créer vos propres applications et profiter des mêmes fonctionnalités que nous utilisons dans Angular, mais cela est entièrement facultatif. Désolé s'il y a eu une certaine confusion sur ce point dans nos annonces.

@EisenbergEffect Mon mauvais. Je le savais et j'aurais dû mieux relire. Pas de café !

Les frameworks ne peuvent pas vraiment contourner les limitations de la plate-forme Web. Comme, nous ne pouvons pas forcer le navigateur à nous laisser écrire sur des attributs IDL en lecture seule (ce qui casse vraiment la liaison bidirectionnelle pour les fichiers), et nous ne pouvons pas forcer le navigateur à nous exposer le système de fichiers, ce qui nous empêche vraiment de le faire rien d'intéressant avec ça

@caitp Je suis ce problème depuis un certain temps maintenant. Je pense qu'il semble y avoir suffisamment de volonté de la communauté pour qu'Angular prenne en charge une simple entrée de sélection de fichier. Actuellement (sauf erreur de ma part), créer une application triviale qui accepte un fichier et le télécharge via XHR à l'aide d'Angular n'a pas de modèle recommandé à suivre ? Cela ressemble à une fonctionnalité qui mérite au moins une certaine attention autre que "désolé, je ne peux pas le faire car la liaison bidirectionnelle n'a pas de sens ici".

Peut-être pouvons-nous réorienter cette conversation vers : « Comment angulaire pourrait-il supporter cela ? » au lieu de « Cela ne correspondra pas à nos modèles actuels ».

La liaison à l'entrée de fichier est certainement possible, je l'ai fait dans un projet précédent pour AngularJS en fait.

Le fait que vous ne puissiez pas effectuer de liaison bidirectionnelle avec les entrées de fichier est une fonctionnalité de sécurité, et cela a du sens. Les auteurs ne pourront jamais définir le chemin du fichier via un script, mais pourquoi ne pas simplement le lier à sens unique ?

Bien sûr, cela brise le paradigme, mais qui se soucie vraiment si cela signifie que vous obtenez un ng-change et la possibilité d'accéder aux fichiers via l'API de fichiers sans hacks ? jQuery peut se lier à un événement de modification sur les entrées de fichier, la méthode Angular est-elle si sacrée que nous ne pouvons pas simplement la lier dans un contrôleur? Est-ce une limitation technique avec l'architecture ou juste une barrière idéologique ?

D'accord, j'étais moins préoccupé par la reliure à 2 voies. Je voulais simplement publier le fichier avec le reste de mon document sans sauter à travers les cerceaux.

Le 20 mai 2014, à 7h53, Justin Arruda < [email protected] [email protected] > a écrit :

@c aitphttps://github.com/caitp Je suis ce problème depuis un certain temps maintenant. Je pense qu'il semble y avoir suffisamment de volonté de la communauté pour qu'Angular prenne en charge une simple entrée de sélection de fichier. Actuellement (sauf erreur de ma part), créer une application triviale qui accepte un fichier et le télécharge via XHR à l'aide d'Angular n'a pas de modèle officiel à suivre ? Cela ne ressemble-t-il pas à une fonctionnalité qui mérite au moins une certaine attention autre que "désolé, je ne peux pas le faire car la liaison bidirectionnelle n'a pas de sens ici".

Peut-être pouvons-nous réorienter cette conversation vers : « Comment angulaire pourrait-il supporter cela ? » au lieu de « Cela ne correspondra pas à nos modèles actuels ».

-
Répondez directement à cet e-mail ou consultez-le sur Gi tHubhttps://github.com/angular/angular.js/issues/1375#issuecomment -43636326.

Ensuite, vous avez un cas où ng-model se comporte de manière très différente pour un contrôle de formulaire particulier, puis vous avez des personnes qui signalent des bogues comme "comment se fait-il que le contrôle de formulaire envoie le mauvais fichier lorsque je change la valeur en "foobarblah.txt" ou autre. API incohérente -> mauvaise.

ngModel n'est pas totalement idéal pour ce genre de choses, en particulier parce que cela signifie que nous avons un modèle spécifique à intégrer, et il est très difficile pour les auteurs d'applications de le désactiver. Il existe des solutions pour cela dans angular.dart et le prototype v2.0.0, donc ce sera mieux à l'avenir. Mais nous ne pouvons vraiment pas ajouter un autre comportement ng-model qui ignore tout ce que ng-model fait actuellement, cela n'aurait aucun sens

accepte un fichier et le télécharge via XHR en utilisant Angular

@guruward, nous ne pouvons pas prendre en charge cela sur tous nos navigateurs cibles pour 1.x sans obliger les gens à utiliser des polyfills shockwave ou similaires. Il existe des modules tiers qui le permettent, et ils peuvent être utilisés à la place. angular-file-upload envoie simultanément les versions natives shockwave polyfill et html5, et choisit la bonne. Ce n'est donc pas une mauvaise solution, fortement recommandé si vous voulez faire cela.

Mais je ne suis pas sûr que ce soit quelque chose que nous puissions mettre dans le noyau, vous devriez demander à Igor ce qu'il pense de l'expédition d'un polyfill à ondes de choc dans le noyau.

Je ne dis pas que c'est un cas d'utilisation que les gens ne voudront jamais faire, je peux comprendre le fait de vouloir le faire, je dis simplement que cela ne rentre pas dans le modèle ngModel et nous oblige à ajouter un peu de cruft supplémentaire afin de prend en charge tous les navigateurs cibles, donc cela brise le cadre de cette façon.

Quel est le mal à utiliser des modules tiers pour cela ?

Ce polyfill ne nécessite pas de flash.

@jreading ce n'est pas un polyfill, et il était livré avec un téléchargeur flash, il l'a probablement encore quelque part.

Ce qu'il fait, c'est s'appuyer sur l'API File, qui n'est pas disponible dans tous les navigateurs cibles, et est donc problématique pour le noyau angulaire 1.x.

Sans cette API, vous n'avez aucun moyen d'accéder au fichier blob sans quelque chose comme shockwave.

Il utilise des iframes au lieu de flash, vous pensez peut-être à ceci . Au lieu de débattre de la sémantique, que diriez-vous d'une feuille de route ? Commençons par ng-change sur l'entrée de fichier pour les navigateurs compatibles avec l'API de fichier.

@jreading malheureusement, cela n'aide pas les navigateurs qui ne sont pas compatibles avec les API, ce qui inclut IE9, qui est toujours pris en charge. Nous ne pouvons pas livrer une API qui fonctionne sur le navigateur pris en charge A mais pas le navigateur B pris en charge dans le noyau sans aucune solution pour les personnes qui dépendent de la prise en charge d'IE9. Et non, une iframe n'expose pas le contenu d'un fichier en tant que blob et ne le rend pas téléchargeable. Hnnggggg.

Il existe des solutions pour cela dans des modules tiers, que les applications peuvent utiliser si elles le jugent approprié. Mettre cela dans le noyau A) donne plus de mal à ces modules tiers, et B) ne prend pas en charge tous les navigateurs cibles, c'est donc un problème.

Ce n'est que mon opinion, peut-être qu'Igor ou quelqu'un d'autre ne sera pas d'accord, mais je ne pense pas que ce soit la bonne approche ici.

Quel est l'inconvénient d'utiliser des modules tiers s'ils fonctionnent pour vous et que vous en avez besoin ?

Jamais vraiment impliqué qu'un blob devait être disponible pour le contrôleur. Je sors sur une branche, mais le cas d'utilisation le plus important que je vois est la possibilité de savoir quand l'entrée du fichier a changé et la possibilité de l'envoyer à un point de terminaison de repos, qui est disponible avec cette solution iframe ou API de fichier et angulaire hacks.

Les modules tiers sont le seul moyen d'apporter des améliorations agressives comme mon article de blog (pas de téléchargement pour vous !!), mais je pourrais simplement retourner la question et demander "qu'y a-t-il de mal à avoir une meilleure API pour les navigateurs modernes ?"

« Qu'est-ce qu'il y a de mal à avoir une meilleure API pour les navigateurs modernes ? »

Cet argument est faible car il ne prend pas en compte le coût d'opportunité ; il y a beaucoup d'autres choses sur lesquelles nous (l'équipe de base) travailler.

Assez juste. On dirait juste un énorme écart et des fruits à portée de main.

Le problème ici n'est pas de savoir comment faire fonctionner cela avec ngModel. Je pense que ngModel pourrait exposer la FileList du champ de saisie sur la portée, mais dans l'autre sens, nous autoriserions uniquement la définition du modèle sur null/undefined pour être pris en charge. les analyseurs/formateurs ne feraient probablement rien et les validateurs feraient simplement des choses simples comme vérifier la présence ou l'absence d'un fichier.

Le problème est (comme mentionné précédemment) que sans la prise en

De plus, essayer de gérer cette entrée d'une manière qui n'est pas compatible avec plusieurs navigateurs ne fait que compliquer la tâche des solutions tierces, qui doivent désormais combattre/désactiver/contourner la solution principale.

des solutions non essentielles qui gèrent cela existent déjà et elles ont été mentionnées dans cette discussion de problème ainsi que dans le numéro précédent

Il y a beaucoup d'autres choses qui ont un impact plus important que nous voulons faire. Je comprends que c'est un cas relativement courant, mais je n'ai toujours pas entendu pourquoi les solutions existantes ne sont pas suffisantes ?

Une partie de l'énergie investie dans cette discussion pourrait-elle être redirigée vers l'amélioration des solutions existantes si elles en ont besoin, ou vers la création d'une nouvelle solution supérieure à celles existantes ?

Je vais fermer ça comme nous avons fermé le #1236. Angular 2 est en cours de construction pour prendre en charge les navigateurs modernes et avec cette prise en charge des fichiers sera facilement disponible.

Je veux simplement savoir quand l'événement de changement se produit afin que je puisse accéder directement à l'élément et récupérer les informations du fichier et les télécharger via AJAJ.

@bjoshuanoah alors

@caitp Je veux tout contrôler dans le contrôleur et non avec une directive.

Si je mets ng-change="uploadFile({$event: $event})"

Je peux avoir $scope.uploadFile(event) dans mon contrôleur. et le gérer là-bas.

Mon cas d'utilisation spécifique est le suivant : télécharger un fichier sur s3, appliquer l'url à mon modèle.

au lieu de cela, je dois entrer dans la portée pour faire la même chose. Très ennuyant:

<input name="highRes" scope="{{contentOptions.currentValue}}" key="value" type="file" onchange="angular.element(this).scope().setFile(this)">

J'aimerais que quelqu'un tue ce problème. donc on peut tous avancer :)

Le 25 juillet 2014, à 9h22, Brian < [email protected] [email protected] > a écrit :

Je veux simplement savoir quand l'événement de changement se produit afin que je puisse accéder directement à l'élément et récupérer les informations du fichier et les télécharger via AJAJ.

-
Répondez directement à cet e-mail ou consultez-le sur Gi tHubhttps://github.com/angular/angular.js/issues/1375#issuecomment -50171714.

+1

+1

+1000000000000000

+1

+1

+1

+1

+100500

+1
Je ne sais pas pourquoi Ajax est un problème. On peut vouloir charger les données d'un fichier csv sur la machine locale dans un modèle angulaire. Si ng-change fonctionnait dans l'entrée de fichier dans Angular, ce serait facile, actuellement ce n'est pas . Ce scénario ne nécessite pas du tout Ajax ou une API de serveur. Je ne sais pas non plus pourquoi c'est fermé ?

Ma solution de contournement actuelle est de faire ce qui suit

 input(type="file", onchange="angular.element(this).scope().onFileSet(this.files)")

et dans mon contrôleur, j'ai juste quelque chose comme

$scope.onFileSet = function(files) { 
// work your magic here 
}

Ça pue à peu près, j'ai l'impression de bâtarder angulaire comme outil. Toute idée sur la façon de le faire d'une manière plus angulaire serait très appréciée.

:coeur coeur:

Voici un voilier : :voilier:

@samccone La fonction scope() n'est-elle pas indisponible lorsque le mode debug est désactivé ?

@geetsce C'est correct (dans 1.3.x et versions ultérieures)

welp, dans 1.2 land tout va bien.

@Narretz avez-vous une meilleure solution ?

Cela fonctionne pour moi, il est inspiré de https://jasonturim.wordpress.com/2013/09/01/angularjs-drag-and-drop

<input type="file" multiple="multiple" data-dbinf-on-files-selected="chooseAFunctionName(selectedFileList)">
<script>
/**Directive to propagate selected files from an HTML input element with type="file"
 * to the surrounding AngularJS controller.
 */
myApp.directive('dbinfOnFilesSelected', [function() {
    return {
        restrict: 'A',
        scope: {
              //attribute data-dbinf-on-files-selected (normalized to dbinfOnFilesSelected) identifies the action
              //to take when file(s) are selected. The '&' says to  execute the expression for attribute
              //data-dbinf-on-files-selected in the context of the parent scope. Note though that this '&'
              //concerns visibility of the properties and functions of the parent scope, it does not
              //fire the parent scope's $digest (dirty checking): use $scope.$apply() to update views
              //(calling scope.$apply() here in the directive had no visible effect for me).
            dbinfOnFilesSelected: '&'
        },
        link: function(scope, element, attr, ctrl) {
            element.bind("change", function()
            {  //match the selected files to the name 'selectedFileList', and
               //execute the code in the data-dbinf-on-files-selected attribute
             scope.dbinfOnFilesSelected({selectedFileList : element[0].files});
            });
        }
    }
}]);

myApp.controller('myController', ['$scope', function($scope) {
    $scope.chooseAFunctionName = function (filelist) {
        for (var i = 0; i < filelist.length; ++i) {
            var file = filelist.item(i);
            //do something with file; remember to call $scope.$apply() to trigger $digest (dirty checking)
            alert(file.name);
           }
    };
}]);
</script>

+1

+1

Cela n'arrivera pas... Laisse tomber, laisse tomber...

+1

Comme l'a dit @samccone ,

input(type="file", onchange="angular.element(this).scope().onFileSet(this.files)")

Ce n'est pas la façon angulaire de faire les choses. C'est étrange.

+1

+1

+1

hey @caitp @Narretz si vous souhaitez que je puisse préparer un PR pour cela pour la branche 1.2x, faites-moi savoir si c'est quelque chose que vous souhaitez ajouter ou non. Je comprends les problèmes de sécurité et le manque de prise en charge de plusieurs navigateurs en ce qui concerne l'accès à l'objet de fichier réel, mais il semble que la prise en charge de base pour détecter quand une entrée de fichier a changé (passer dans l'événement d'origine) fournirait suffisamment de crochet pour que les gens travaillent leur magie.

Merci encore pour tout ce que vous faites :palm_tree:

+1

+1

+1

+1

+1

ng-file-upload fonctionne très bien.

+1 pour @neokyol !! ça marche super bien !

cette fonctionnalité commune doit être par défaut dans le framework

utile

+1

+1

+1

+1

+1

cela a fonctionné pour moi, peut aider

angular.module('app', [])
  .controller('MainCtrl', MainCtrl)
  .directive('fileChange', fileChange);

  function MainCtrl($scope) {
    $scope.upload = function () {
      // do something with the file
      alert($scope.file.name);
    };
  }

  function fileChange() {
    return {
      restrict: 'A',
      require: 'ngModel',
      scope: {
        fileChange: '&'
      },
      link: function link(scope, element, attrs, ctrl) {
        element.on('change', onChange);

        scope.$on('destroy', function () {
          element.off('change', onChange);
        });

        function onChange() {
          ctrl.$setViewValue(element[0].files[0]);
          scope.fileChange();
        }
      }
    };
  }
<div ng-app="app" ng-controller="MainCtrl">
  <input type="file" file-change="upload()" ng-model="file">
</div>

http://plnkr.co/edit/JYX3Pcq18gH3ol5XSizw?p=preview

+1

+1

+1

+1

+100000000000000000000000

+1

+1

@dciccale pouvez-vous s'il vous plaît fournir un exemple de plunker.

+1

+1

+1 Il devrait y avoir une directive intégrée dans la bibliothèque principale pour cela. C'est assez ridicule

+1

+1
la fonctionnalité est-elle prévue pour l'une des prochaines versions ?

+1

+1

Comment procéder dans les projets où $scope n'est jamais injecté dans le contrôleur. J'utilise laravel angulaire qui utilise les méthodes GULP et ES6 pour déclarer les contrôleurs.

c'est à dire

class TestController{
    constructor(API){
        'ngInject';
        this.API = API
    }

    $onInit(){
        this.file = null;
    }
    upload() {
        console.log(this.file)
    }
    fileChanged(elm) {
        console.log('hey')
        this.file = elm.file;
        this.$apply();
    }
}

export const TestComponent = {
    templateUrl: './views/app/components/test/test.component.html',
    controller: TestController,
    controllerAs: 'vm',
    bindings: {}
}

J'ai trouvé un travail autour je crois. http://stackoverflow.com/questions/38449126/how-to-set-up-ng-file-upload-in-laravel-angular-project/38486379#38486379

+1

@ntrp @guruward @coli @lgersman @jgoldber @Siyfion
Comment avez-vous corrigé la validation pour
Ma validation :
this.catalougeForm = this.catalougeFormBuilder.group({
catalougeIconName : ['', Validators.required]
});
HTML :
(change)="changeListener($événement)">

Mon validateur considère la valeur catalougeIconName comme vide/nulle après le téléchargement.
L'image est envoyée, mais le validateur ne fonctionne pas

Des mises à jour à ce sujet ?

Les mises à jour ?

Cette page vous a été utile?
0 / 5 - 0 notes