17

I am trying to run my upload() function when a file input changes. However, I can't make it work.

HTML:

<input type="file" ng-model="image" ng-change="uploadImage()">

JS:

$scope.uploadImage = function() {
    console.log('Changed');
}

What am I doing wrong?

Pixark
  • 385
  • 1
  • 4
  • 13
  • 2
    possible duplicate of [AngularJs: How to check for changes in file input fields?](http://stackoverflow.com/questions/17922557/angularjs-how-to-check-for-changes-in-file-input-fields) – Ali Gonabadi Jun 15 '15 at 10:29

4 Answers4

54

Try this out:- http://jsfiddle.net/adiioo7/fA968/

JS:-

function myCtrl($scope) {
    $scope.uploadImage = function () {
        console.log("Changed");
    }
}

HTML:-

<div ng-app ng-controller="myCtrl">
    <input type="file" ng-model="image" onchange="angular.element(this).scope().uploadImage()" />
</div>
Aditya Singh
  • 9,512
  • 5
  • 32
  • 55
  • 2
    @Pixark Does this answer your question? – Aditya Singh Nov 23 '13 at 15:00
  • 3
    I just ran into this, and your solution works. It's a shame that ng-change doesn't seem to work on file uploads though. – Jason Farnsworth Mar 14 '14 at 05:42
  • This works, but how would you pass $event? Just putting $event as a function parameter gives a not defined error. – Matt McDonald Apr 01 '14 at 12:27
  • This answer should be accepted... but, why must be done this way? `angular.element(this).scope().XXX()` instead of `XXX()` ..Is there a reason beside of just working? – sports Oct 06 '14 at 23:44
  • @sports Since `onchange` is an HTML attribute (instead of an Angular directive) it doesn't know about the functions defined in your controller (under `$scope`) that's why you need to make an explicit reference to the current scope with `angular.element(this).scope()` – Pau Fracés Mar 25 '15 at 19:14
  • `angular.element(this).scope().uploadImage(this)` and use `function(input){input.files[0] ... }` – Alexmelyon Sep 22 '15 at 08:06
  • 10
    This won't work in except in debug mode; this might be better: http://stackoverflow.com/a/19647381/2056448 – Casey Dec 04 '15 at 19:28
  • Plus one for teaching me the use of "this" instead of passing the controler name. Thx! – domih May 31 '16 at 18:00
  • Also doesn't file a second time if you select the same file again. – James Aug 23 '16 at 10:36
  • You can get it to fire a second time if you select the same file again by using this `onclick="this.value=null"`, if that's your need. – Tim Harker Mar 14 '19 at 23:29
  • This approach is too hackish, a custom directive is more appropriate – Yonatan Naor May 26 '19 at 14:39
  • when use this upload on a _forloop_.,how can pass **index** through this `uploadImage()` – safeena rasak Jun 01 '20 at 12:37
  • This seems not to be working when debug is false. The scope() is undefined: Here is a thread about this: https://github.com/angular/angular.js/issues/9515 – sandrob Jun 29 '20 at 10:09
53

Here's a directive I made that accomplishes what you are asking. If I'm not mistaken, I think the other solutions won't work in production mode, but this one does. It is used like so:

<input ng-upload-change="fileChanged($event)" />

In your controller:

$scope.fileChanged = function($event){
    var files = $event.target.files;
}

And for the directive to include somewhere in your code:

angular.module("YOUR_APP_NAME").directive("ngUploadChange",function(){
    return{
        scope:{
            ngUploadChange:"&"
        },
        link:function($scope, $element, $attrs){
            $element.on("change",function(event){
                $scope.$apply(function(){
                    $scope.ngUploadChange({$event: event})
                })
            })
            $scope.$on("$destroy",function(){
                $element.off();
            });
        }
    }
});

This code is released into the public domain, no attributions required.

You should also be aware that if somebody selects a file, closes the file input, and then selects the same file again later on, it won't fire the change function again. To fix this, I've created a more complete directive that replaces the input under the hood each time you use it. I put it on github here:

https://github.com/dtruel/angular-file-input/tree/master

user3413723
  • 11,147
  • 6
  • 55
  • 64
  • 7
    Someone give this man a medal. So sad I'm the only upvote. Your solution works like a charm. Thanks for that. I think it is more angular than the others. – Asier Paz Feb 10 '17 at 17:55
3

Another interesting way to listen to file input change is with a watch over the ng-model attribute of the input file.

Like this:

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

JS Code ->

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

Hope this helps.

halbano
  • 1,135
  • 14
  • 34
-5

Use ng-file-select="upload($files)"

'<input type="file" class="form-control" ng-model="alunos.file" accept="image/*" ng-file-select="upload($files)"/>'

where upload is a function:$scope.upload = function(file){ console.log(file); };