Si vous voulez quelque chose d'un peu plus élégant / intégré, vous pouvez utiliser un décorateur pour étendre la input
directive avec le support de type=file
. La principale mise en garde à garder à l'esprit est que cette méthode ne fonctionnera pas dans IE9 car IE9 n'a pas implémenté l'API de fichier . L'utilisation de JavaScript pour télécharger des données binaires quel que soit leur type via XHR n'est tout simplement pas possible en natif dans IE9 ou antérieur (l'utilisation de ActiveXObject
pour accéder au système de fichiers local ne compte pas car l'utilisation d'ActiveX demande simplement des problèmes de sécurité).
Cette méthode exacte nécessite également AngularJS 1.4.x ou version ultérieure, mais vous pourrez peut-être l'adapter à l'utilisation $provide.decorator
plutôt que angular.Module.decorator
- j'ai écrit cet essentiel pour montrer comment le faire tout en se conformant au guide de style AngularJS de John Papa :
(function() {
'use strict';
/**
* @ngdoc input
* @name input[file]
*
* @description
* Adds very basic support for ngModel to `input[type=file]` fields.
*
* Requires AngularJS 1.4.x or later. Does not support Internet Explorer 9 - the browser's
* implementation of `HTMLInputElement` must have a `files` property for file inputs.
*
* @param {string} ngModel
* Assignable AngularJS expression to data-bind to. The data-bound object will be an instance
* of {@link https://developer.mozilla.org/en-US/docs/Web/API/FileList `FileList`}.
* @param {string=} name Property name of the form under which the control is published.
* @param {string=} ngChange
* AngularJS expression to be executed when input changes due to user interaction with the
* input element.
*/
angular
.module('yourModuleNameHere')
.decorator('inputDirective', myInputFileDecorator);
myInputFileDecorator.$inject = ['$delegate', '$browser', '$sniffer', '$filter', '$parse'];
function myInputFileDecorator($delegate, $browser, $sniffer, $filter, $parse) {
var inputDirective = $delegate[0],
preLink = inputDirective.link.pre;
inputDirective.link.pre = function (scope, element, attr, ctrl) {
if (ctrl[0]) {
if (angular.lowercase(attr.type) === 'file') {
fileInputType(
scope, element, attr, ctrl[0], $sniffer, $browser, $filter, $parse);
} else {
preLink.apply(this, arguments);
}
}
};
return $delegate;
}
function fileInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
element.on('change', function (ev) {
if (angular.isDefined(element[0].files)) {
ctrl.$setViewValue(element[0].files, ev && ev.type);
}
})
ctrl.$isEmpty = function (value) {
return !value || value.length === 0;
};
}
})();
Pourquoi cela n'a-t-il pas été fait en premier lieu? La prise en charge d'AngularJS est destinée à n'atteindre que IE9. Si vous n'êtes pas d'accord avec cette décision et que vous pensez qu'ils auraient dû le mettre de toute façon, sautez le wagon vers Angular 2+ car un meilleur support moderne est littéralement la raison pour laquelle Angular 2 existe.
Le problème est (comme cela a été mentionné précédemment) que sans le support de l'API de fichier, faire cela correctement est impossible pour le noyau étant donné que notre base de référence est IE9 et le polyfilling de ce genre de choses est hors de question pour le noyau.
De plus, essayer de gérer cette entrée d'une manière qui n'est pas compatible avec tous les navigateurs ne fait que compliquer la tâche des solutions tierces, qui doivent désormais combattre / désactiver / contourner la solution principale.
...
Je vais fermer cela juste au moment où nous fermons # 1236. Angular 2 est en cours de construction pour prendre en charge les navigateurs modernes et avec ce fichier, la prise en charge sera facilement disponible.