Si desea algo un poco más elegante / integrado, puede usar un decorador para ampliar la input
directiva con soporte type=file
. La advertencia principal a tener en cuenta es que este método no funcionará en IE9 ya que IE9 no implementó la API de archivos . El uso de JavaScript para cargar datos binarios independientemente del tipo a través de XHR simplemente no es posible de forma nativa en IE9 o versiones anteriores (el uso ActiveXObject
para acceder al sistema de archivos local no cuenta, ya que el uso de ActiveX solo requiere problemas de seguridad).
Este método exacto también requiere AngularJS 1.4.xo posterior, pero es posible que pueda adaptar esto para usarlo en $provide.decorator
lugar de angular.Module.decorator
: Escribí esta esencia para demostrar cómo hacerlo mientras se ajusta a la guía de estilo 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;
};
}
})();
¿Por qué no se hizo esto en primer lugar? El soporte de AngularJS está destinado a llegar tan atrás como IE9. Si no está de acuerdo con esta decisión y cree que deberían haberlo puesto de todos modos, salte al carro a Angular 2+ porque un mejor soporte moderno es, literalmente, por qué existe Angular 2.
El problema es (como se mencionó anteriormente) que sin el soporte de la API de archivos, hacer esto correctamente no es factible para el núcleo dado que nuestra línea de base es IE9 y el relleno múltiple de este material está fuera de cuestión para el núcleo.
Además, tratar de manejar esta entrada de una manera que no sea compatible con navegadores cruzados solo hace que sea más difícil para las soluciones de terceros, que ahora tienen que luchar / deshabilitar / solucionar la solución central.
...
Voy a cerrar esto justo cuando cerramos # 1236. Angular 2 se está creando para admitir navegadores modernos y con ese soporte de archivos estará fácilmente disponible.