AngularJs: Comment vérifier les changements dans les champs de saisie de fichiers?
Je suis nouveau à angular. J'essaie de lire le chemin du fichier téléchargé à partir du champ 'file' HTML chaque fois qu'un 'changement' se produit sur ce champ. Si j'utilise 'onChange' cela fonctionne mais quand je l'utilise de manière 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>
FileNameChaged () n'appelle jamais. Firebug ne montre pas non plus d'erreur.
14 réponses
Pas de support de liaison pour le contrôle de téléchargement de fichiers
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()" />
Pouvez-vous essayer
<input type="file" style="display:none"
id="file" name='file' onchange="angular.element(this).scope().fileNameChanged()" />
Remarque: cela nécessite que l'application angulaire soit toujours en mode de débogage . Cela ne fonctionnera pas dans le code de production si le mode débogage est désactivé.
Et dans votre fonction change au lieu de
$scope.fileNameChanged = function() {
alert("select file");
}
Pouvez-vous essayer
$scope.fileNameChanged = function() {
console.log("select file");
}
Voici un exemple de travail de téléchargement de fichiers avec drag drop téléchargement de fichiers peut être utile http://jsfiddle.net/danielzen/utp7j/
Informations De Téléchargement De Fichier Angulaire
URL pour le téléchargement du fichier AngularJS dans ASP.Net
Http://cgeers.com/2013/05/03/angularjs-file-upload/
Téléchargement multi-fichiers natif AngularJs avec progression 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 en utilisant iframe
J'ai fait une petite directive pour écouter les modifications d'entrée de fichier.
Vue.html:
<input type="file" custom-on-change="uploadFile">
Le Contrôleur.js:
app.controller('myCtrl', function($scope){
$scope.uploadFile = function(event){
var files = event.target.files;
};
});
La 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();
});
}
};
});
C'est un raffinement de certains des autres, les données se retrouveront dans un modèle ng, ce qui est normalement ce que vous voulez.
Markup (il suffit de créer 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();
});
}
};
});
La manière propre est d'écrire votre propre directive pour se lier à l'événement" change". Juste pour vous faire savoir que IE9 ne prend pas en charge FormData, donc vous ne pouvez pas vraiment obtenir l'objet file De l'événement change.
Vous pouvez utiliser la bibliothèque ng-file-upload qui prend déjà en charge IE avec FileAPI polyfill et simplifie 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);
});
}
}
}];
J'ai développé l'idée de @Stuart Axon d'ajouter une liaison bidirectionnelle pour l'entrée du fichier (c'est-à-dire permettre de réinitialiser l'entrée en réinitialisant la valeur du modèle à 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
Semblable à certaines des autres bonnes réponses ici, j'ai écrit une directive pour résoudre ce problème, mais cette implémentation 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 voir, vous pouvez injecter les fichiers sélectionnés dans votre gestionnaire d'événement que vous donneriez à un $objet d'événement dans toute ng gestionnaire d'événement.
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);
}
};
}]);
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);
};
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 parente. Vous pouvez également donner quelques 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é
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()">
Solution trop complète base 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 hack sur angular mais qui fait le travail [TriggerEvent ne fonctionne pas comme prévu]
La solution:
- Placez le champ de saisie dans display: none [le champ de saisie 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 l'image est cliqué simuler une action DOM 'click' 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!!!
};
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");
}
Une autre façon intéressante d'écouter les changements d'entrée de fichier est de surveiller l'attribut ng-model du fichier d'entrée. Bien sûr FileModel est une directive personnalisée.
Comme ceci:
HTML -> <input type="file" file-model="change.fnEvidence">
Code JS- >
$scope.$watch('change.fnEvidence', function() {
alert("has changed");
});
J'espère que cela peut aider quelqu'un.
Travailler Démo de "fichiers d'entrée" de la Directive qui Fonctionne avec ng-change
1
Pour un <input type=file>
élément de travail de la ng-changement de directive, il a besoin d'un personnalisé directive qui fonctionne avec la ng-model directive.
<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>
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'écouteur d'événement comme ceci:
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 une délégation d'événement jQuery. Ici, l'auditeur est attaché à l'élément racine de la directive. Lorsque l'événement est déclenché, il apparaîtra dans l'élément enregistré et jQuery déterminera si l'événement provient d'un élément interne correspondant au sélecteur défini. Si c'est le cas, le gestionnaire d'incendie.
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
oung-switch
)