web-dev-qa-db-fra.com

AngularJs: Comment vérifier les changements dans les champs de saisie du fichier?

Je suis nouveau à angular. J'essaie de lire le chemin du fichier téléchargé à partir du champ 'fichier' HTML chaque fois qu'un 'changement' se produit sur ce champ. Si j'utilise 'onChange' cela fonctionne mais quand je l'utilise de façon angulaire en utilisant 'ng-change' cela ne fonctionne pas.

<script>
   var DemoModule = angular.module("Demo",[]);
   DemoModule .controller("form-cntlr",function($scope){
   $scope.selectFile = function()
   {
        $("#file").click();
   }
   $scope.fileNameChaged = function()
   {
        alert("select file");
   }
});
</script>

<div ng-controller="form-cntlr">
    <form>
         <button ng-click="selectFile()">Upload Your File</button>
         <input type="file" style="display:none" 
                          id="file" name='file' ng-Change="fileNameChaged()"/>
    </form>  
</div>

NomFichierChagé () n'appelle jamais. Firebug ne montre pas non plus d'erreur.

265
manish

Pas de support de liaison pour le contrôle de téléchargement de fichier

https://github.com/angular/angular.js/issues/1375

<div ng-controller="form-cntlr">
        <form>
             <button ng-click="selectFile()">Upload Your File</button>
             <input type="file" style="display:none" 
                id="file" name='file' onchange="angular.element(this).scope().fileNameChanged(this)" />
        </form>  
    </div>

au lieu de

 <input type="file" style="display:none" 
    id="file" name='file' ng-Change="fileNameChanged()" />

peux-tu essayer

<input type="file" style="display:none" 
    id="file" name='file' onchange="angular.element(this).scope().fileNameChanged()" />

Remarque: cela nécessite que l'application angular soit toujours en mode débogage . Cela ne fonctionnera pas dans le code de production si le mode débogage est désactivé.

et dans vos changements de fonction au lieu de

$scope.fileNameChanged = function() {
   alert("select file");
}

peux-tu essayer

$scope.fileNameChanged = function() {
  console.log("select file");
}

Vous trouverez ci-dessous un exemple pratique de téléchargement de fichier avec glisser-déposer. Le téléchargement de fichier peut être utile http://jsfiddle.net/danielzen/utp7j/

Informations sur le téléchargement de fichier angulaire

URL pour le téléchargement de fichier AngularJS dans ASP.Net

http://cgeers.com/2013/05/03/angularjs-file-upload/

AngularJs upload natif multi-fichiers avec des progrès avec NodeJS

http://jasonturim.wordpress.com/2013/09/12/angularjs-native-multi-file-upload-with-progress/

ngUpload - Un service AngularJS pour le téléchargement de fichiers à l'aide d'iframe

http://ngmodules.org/modules/ngUpload

236
JQuery Guru

J'ai fait une petite directive d'écouter les modifications apportées aux entrées de fichier.

Voir JSFiddle

view.html:

<input type="file" custom-on-change="uploadFile">

controller.js:

app.controller('myCtrl', function($scope){
    $scope.uploadFile = function(event){
        var files = event.target.files;
    };
});     

directive.js:

app.directive('customOnChange', function() {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      var onChangeHandler = scope.$eval(attrs.customOnChange);
      element.on('change', onChangeHandler);
      element.on('$destroy', function() {
        element.off();
      });

    }
  };
});
454
sqren

Ceci est un raffinement de certains des autres autour, les données se retrouveront dans un modèle ng, qui est normalement ce que vous voulez.

Balisage (créez simplement un fichier de données d'attribut pour que la directive puisse le trouver)

<input
    data-file
    id="id_image" name="image"
    ng-model="my_image_model" type="file">

JS

app.directive('file', function() {
    return {
        require:"ngModel",
        restrict: 'A',
        link: function($scope, el, attrs, ngModel){
            el.bind('change', function(event){
                var files = event.target.files;
                var file = files[0];

                ngModel.$setViewValue(file);
                $scope.$apply();
            });
        }
    };
});
37
Stuart Axon

La méthode la plus simple consiste à écrire votre propre directive pour la lier à l'événement "change" . Juste pour vous informer que IE9 ne prend pas en charge FormData, vous ne pouvez donc pas obtenir l'objet fichier à partir de l'événement change.

Vous pouvez utiliser ng-file-upload library qui prend déjà en charge IE avec FileAPI polyfill et simplifier la publication du fichier sur le serveur. Il utilise une directive pour y parvenir. 

<script src="angular.min.js"></script>
<script src="ng-file-upload.js"></script>

<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) {
    //$files: an array of files selected, each file has name, size, and type.
    for (var i = 0; i < $files.length; i++) {
      var $file = $files[i];
      Upload.upload({
        url: 'my/upload/url',
        data: {file: $file}
      }).then(function(data, status, headers, config) {
        // file is uploaded successfully
        console.log(data);
      }); 
    }
  }
}];
27
danial

J'ai développé l'idée de @Stuart Axon d'ajouter une liaison bidirectionnelle pour l'entrée de fichier (c'est-à-dire, autoriser la réinitialisation de l'entrée en réinitialisant la valeur du modèle sur null):

app.directive('bindFile', [function () {
    return {
        require: "ngModel",
        restrict: 'A',
        link: function ($scope, el, attrs, ngModel) {
            el.bind('change', function (event) {
                ngModel.$setViewValue(event.target.files[0]);
                $scope.$apply();
            });

            $scope.$watch(function () {
                return ngModel.$viewValue;
            }, function (value) {
                if (!value) {
                    el.val("");
                }
            });
        }
    };
}]);

Démo

26
JLRishe

Semblable à certaines des autres bonnes réponses ici, j'ai écrit une directive pour résoudre ce problème, mais cette mise en œuvre reflète plus étroitement la manière angulaire d'attacher des événements. 

Vous pouvez utiliser la directive comme ceci:

HTML

<input type="file" file-change="yourHandler($event, files)" />

Comme vous pouvez le constater, vous pouvez injecter les fichiers sélectionnés dans votre gestionnaire d’événements, comme vous injecteriez un objet $ event dans n’importe quel gestionnaire d’événements ng.

Javascript

angular
  .module('yourModule')
  .directive('fileChange', ['$parse', function($parse) {

    return {
      require: 'ngModel',
      restrict: 'A',
      link: function ($scope, element, attrs, ngModel) {

        // Get the function provided in the file-change attribute.
        // Note the attribute has become an angular expression,
        // which is what we are parsing. The provided handler is 
        // wrapped up in an outer function (attrHandler) - we'll 
        // call the provided event handler inside the handler()
        // function below.
        var attrHandler = $parse(attrs['fileChange']);

        // This is a wrapper handler which will be attached to the
        // HTML change event.
        var handler = function (e) {

          $scope.$apply(function () {

            // Execute the provided handler in the directive's scope.
            // The files variable will be available for consumption
            // by the event handler.
            attrHandler($scope, { $event: e, files: e.target.files });
          });
        };

        // Attach the handler to the HTML change event 
        element[0].addEventListener('change', handler, false);
      }
    };
  }]);
19
Simon Robb

Cette directive transmet également les fichiers sélectionnés:

/**
 *File Input - custom call when the file has changed
 */
.directive('onFileChange', function() {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      var onChangeHandler = scope.$eval(attrs.onFileChange);

      element.bind('change', function() {
        scope.$apply(function() {
          var files = element[0].files;
          if (files) {
            onChangeHandler(files);
          }
        });
      });

    }
  };
});

Le HTML, comment l'utiliser

<input type="file" ng-model="file" on-file-change="onFilesSelected">

Dans mon contrôleur:

$scope.onFilesSelected = function(files) {
     console.log("files - " + files);
};
16
ingaham

Je recommande de créer une directive

<input type="file" custom-on-change handler="functionToBeCalled(params)">

app.directive('customOnChange', [function() {
        'use strict';

        return {
            restrict: "A",

            scope: {
                handler: '&'
            },
            link: function(scope, element){

                element.change(function(event){
                    scope.$apply(function(){
                        var params = {event: event, el: element};
                        scope.handler({params: params});
                    });
                });
            }

        };
    }]);

cette directive peut être utilisée plusieurs fois, elle utilise sa propre portée et ne dépend pas de la portée parent. Vous pouvez également donner des paramètres à la fonction de gestionnaire. La fonction de gestionnaire sera appelée avec l'objet scope, qui était actif lorsque vous avez modifié l'entrée. $ apply met à jour votre modèle chaque fois que l'événement change est appelé 

6
Julia Usanova

La version angulaire jqLite la plus simple.

JS:

.directive('cOnChange', function() {
    'use strict';

    return {
        restrict: "A",
        scope : {
            cOnChange: '&'
        },
        link: function (scope, element) {
            element.on('change', function () {
                scope.cOnChange();
        });
        }
    };
});

HTML:

<input type="file" data-c-on-change="your.functionName()">
4
Jonáš Krutil

Démo de travail de la directive "fichiers-entrée" qui fonctionne avec ng-change1

Pour qu'un élément <input type=file> fonctionne avec la directive ng-change , il faut une directive custom qui fonctionne avec la directive ng-model .

<input type="file" files-input ng-model="fileList" 
       ng-change="onInputChange()" multiple />

La démo

angular.module("app",[])
.directive("filesInput", function() {
  return {
    require: "ngModel",
    link: function postLink(scope,elem,attrs,ngModel) {
      elem.on("change", function(e) {
        var files = elem[0].files;
        ngModel.$setViewValue(files);
      })
    }
  }
})

.controller("ctrl", function($scope) {
     $scope.onInputChange = function() {
         console.log("input change");
     };
})
<script src="//unpkg.com/angular/angular.js"></script>
  <body ng-app="app" ng-controller="ctrl">
    <h1>AngularJS Input `type=file` Demo</h1>
    
    <input type="file" files-input ng-model="fileList" 
           ng-change="onInputChange()" multiple />
    
    <h2>Files</h2>
    <div ng-repeat="file in fileList">
      {{file.name}}
    </div>
  </body>

1
georgeawg

Les éléments angulaires (tels que l'élément racine d'une directive) sont des objets jQuery [Lite]. Cela signifie que nous pouvons enregistrer l'auditeur d'événement de la manière suivante:

link($scope, $el) {
    const fileInputSelector = '.my-file-input'

    function setFile() {
        // access file via $el.find(fileInputSelector).get(0).files[0]
    }

    $el.on('change', fileInputSelector, setFile)
}

C'est la délégation d'événements jQuery. Ici, l'auditeur est attaché à l'élément racine de la directive. Lorsque l'événement est déclenché, il est affiché dans l'élément enregistré et jQuery détermine si l'événement provient d'un élément interne correspondant au sélecteur défini. Si c'est le cas, le gestionnaire va tirer.

Les avantages de cette méthode sont:

  • le gestionnaire est lié à l'élément $ qui sera automatiquement nettoyé lorsque la portée de la directive sera détruite.
  • pas de code dans le modèle
  • fonctionnera même si le délégué cible (entrée) n'a pas encore été rendu lorsque vous enregistrez le gestionnaire d'événements (par exemple, lorsque vous utilisez ng-if ou ng-switch)

http://api.jquery.com/on/

0
Matt S

Je l'ai fait comme ça;

<!-- HTML -->
<button id="uploadFileButton" class="btn btn-info" ng-click="vm.upload()">    
<span  class="fa fa-Paperclip"></span></button>
<input type="file" id="txtUploadFile" name="fileInput" style="display: none;" />
// self is the instance of $scope or this
self.upload = function () {
   var ctrl = angular.element("#txtUploadFile");
   ctrl.on('change', fileNameChanged);
   ctrl.click();
}

function fileNameChanged(e) {
    console.log(self.currentItem);
    alert("select file");
}
0
Ali Sakhi

Vous pouvez simplement ajouter le code ci-dessous dans onchange et il détectera le changement. vous pouvez écrire une fonction sur X click ou quelque chose pour supprimer les données du fichier.

document.getElementById(id).value = "";
0
Jijo Thomas

Solution trop complète basée sur:

`onchange="angular.element(this).scope().UpLoadFile(this.files)"`

Un moyen simple de masquer le champ de saisie et de le remplacer par une image, ici après une solution, qui nécessite également un piratage angulaire mais qui fait l'affaire [TriggerEvent ne fonctionne pas comme prévu]

La solution:

  • placez le champ d'entrée dans display: none [le champ d'entrée existe dans le DOM mais n'est pas visible]
  • placez votre image juste après Sur l’image utilisez nb-click () pour activer une méthode

Lorsque vous cliquez sur l'image, simulez une action DOM. Cliquez sur le champ de saisie. Et voilà!

 var tmpl = '<input type="file" id="{{name}}-filein"' + 
             'onchange="angular.element(this).scope().UpLoadFile(this.files)"' +
             ' multiple accept="{{mime}}/*" style="display:none" placeholder="{{placeholder}}">'+
             ' <img id="{{name}}-img" src="{{icon}}" ng-click="clicked()">' +
             '';
   // Image was clicked let's simulate an input (file) click
   scope.inputElem = elem.find('input'); // find input in directive
   scope.clicked = function () {
         console.log ('Image clicked');
         scope.inputElem[0].click(); // Warning Angular TriggerEvent does not work!!!
    };
0
Fulup

Un autre moyen intéressant d’écouter les modifications d’entrée dans le fichier consiste à surveiller l’attribut ng-model du fichier d’entrée. Bien sûr, FileModel est une directive personnalisée.

Comme ça:

HTML -> <input type="file" file-model="change.fnEvidence">

Code JS ->

$scope.$watch('change.fnEvidence', function() {
                    alert("has changed");
                });

J'espère que ça peut aider quelqu'un.

0
halbano