AngularJs: ¿Cómo verificar cambios en los campos de entrada de archivos?
ng-init (14)
Demostración de trabajo de la directiva de "entrada de archivos" que funciona con ng-change
1
Para hacer que un elemento <input type=file>
funcione con la directiva ng-change , necesita una directiva personalizada que funcione con la directiva ng-model .
<input type="file" files-input ng-model="fileList"
ng-change="onInputChange()" multiple />
La DEMO
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>
Soy nuevo en angular. Estoy intentando leer la ruta del archivo cargado desde el campo ''archivo'' de HTML cada vez que ocurre un ''cambio'' en este campo Si uso ''onChange'' funciona, pero cuando lo uso de forma angular usando ''ng-change'' no funciona.
<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 () nunca llama. Firebug tampoco muestra ningún error.
Al igual que algunas de las otras buenas respuestas aquí, escribí una directiva para resolver este problema, pero esta implementación refleja mejor la forma angular de adjuntar eventos.
Puedes usar la directiva así:
HTML
<input type="file" file-change="yourHandler($event, files)" />
Como puede ver, puede inyectar los archivos seleccionados en su controlador de eventos, como inyectaría un objeto $ event en cualquier controlador de eventos 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);
}
};
}]);
Base de solución demasiado completa en:
`onchange="angular.element(this).scope().UpLoadFile(this.files)"`
Una forma sencilla de ocultar el campo de entrada y reemplazarlo con una imagen, aquí después de una solución, que también requiere un corte en angular pero que hace el trabajo [TriggerEvent no funciona como se esperaba]
La solución:
- coloque el campo de entrada en la pantalla: ninguno [el campo de entrada existe en el DOM pero no está visible]
- coloca tu imagen justo después de En la imagen usa nb-click () para activar un método
Cuando se hace clic en la imagen, se simula una acción DOM ''clic'' en el campo de entrada. 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!!!
};
Esta directiva pasa también los archivos seleccionados:
/**
*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);
}
});
});
}
};
});
El HTML, cómo usarlo:
<input type="file" ng-model="file" on-file-change="onFilesSelected">
En mi controlador:
$scope.onFilesSelected = function(files) {
console.log("files - " + files);
};
Este es un refinamiento de algunos de los demás, los datos terminarán en un modelo ng, que normalmente es lo que usted quiere.
Marca (solo haga un archivo de datos de atributos para que la directiva pueda encontrarlo)
<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();
});
}
};
});
He ampliado la idea de @Stuart Axon de agregar un enlace bidireccional para la entrada del archivo (es decir, permitir restablecer la entrada restableciendo el valor del modelo a cero):
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("");
}
});
}
};
}]);
Hice una pequeña directiva para escuchar los cambios de entrada de archivos.
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;
};
});
directiva.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();
});
}
};
});
La forma limpia es escribir su propia directiva para enlazar al evento "cambiar". Solo para hacerle saber que IE9 no admite FormData, por lo que realmente no puede obtener el objeto de archivo del evento de cambio.
Puede usar la biblioteca ng-file-upload que ya es compatible con IE con polyfill FileAPI y simplificar la publicación del archivo en el servidor. Utiliza una directiva para lograr esto.
<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);
});
}
}
}];
La versión más simple de Angular jqLite.
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()">
Lo he hecho así;
<!-- 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");
}
Los elementos angulares (como el elemento raíz de una directiva) son objetos jQuery [Lite]. Esto significa que podemos registrar el oyente del evento de esta manera:
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)
}
Esta es la delegación de eventos de jQuery. Aquí, el oyente se adjunta al elemento raíz de la directiva. Cuando se desencadena el evento, se acelerará hasta el elemento registrado y jQuery determinará si el evento se originó en un elemento interno que coincide con el selector definido. Si lo hace, el manejador disparará.
Los beneficios de este método son:
- el controlador está vinculado al elemento $ que se limpiará automáticamente cuando se destruya el ámbito de la directiva.
- sin código en la plantilla
- funcionará incluso si el delegado objetivo (entrada) aún no se ha procesado cuando registra el controlador de eventos (como cuando se usa
ng-if
ong-switch
)
No hay soporte de enlace para el control de carga de archivos
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>
en lugar de
<input type="file" style="display:none"
id="file" name=''file'' ng-Change="fileNameChanged()" />
puedes intentar
<input type="file" style="display:none"
id="file" name=''file'' onchange="angular.element(this).scope().fileNameChanged()" />
Nota: esto requiere que la aplicación angular esté siempre en modo de depuración . Esto no funcionará en el código de producción si el modo de depuración está deshabilitado.
y en su función cambia en lugar de
$scope.fileNameChanged = function() {
alert("select file");
}
puedes intentar
$scope.fileNameChanged = function() {
console.log("select file");
}
A continuación se muestra un ejemplo práctico de carga de archivos con la función de arrastrar y soltar la carga de archivos http://jsfiddle.net/danielzen/utp7j/
Información de carga de archivo angular
URL para la carga de archivos AngularJS en ASP.Net
http://cgeers.com/2013/05/03/angularjs-file-upload/
AngularJs carga de archivos múltiples nativa con progreso con NodeJS
http://jasonturim.wordpress.com/2013/09/12/angularjs-native-multi-file-upload-with-progress/
ngUpload: un servicio AngularJS para cargar archivos usando iframe
Otra forma interesante de escuchar los cambios en la entrada de archivos es observar el atributo ng-model del archivo de entrada. Por supuesto FileModel es una directiva personalizada.
Me gusta esto:
HTML -> <input type="file" file-model="change.fnEvidence">
Código JS ->
$scope.$watch(''change.fnEvidence'', function() {
alert("has changed");
});
Espero que pueda ayudar a alguien.
Recomiendo crear una directiva.
<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});
});
});
}
};
}]);
Esta directiva se puede utilizar muchas veces, utiliza su propio ámbito y no depende del ámbito principal. También puede dar algunos parámetros a la función de controlador. La función del controlador se llamará con el objeto de alcance, que estaba activo cuando cambió la entrada. $ apply actualiza su modelo cada vez que se llama al evento de cambio