I copied a custom directive that watches for changes on form file inputs.
angular.module('customDirective', [])
.directive('ngFileInputChange', function() {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var onChangeHandler = scope.$eval(attrs.ngFileInputChange);
element.bind('change', onChangeHandler);
}
};
});
Then I use it in the template like so:
<input ng-model="vm.image" ng-file-input-change="vm.base64Test" ...>
And this works fine.
However, this doesn't work:
<input ng-model="vm.image" ng-file-input-change="vm.base64Test()" ...>
Note the ()
at the end of base64Test()
. With a generic ng-click
, the parenthesis are fine, or even required (how else would I pass arguments to the function?) but with the custom directive, parenthesis cause an error.
I only have a vague understanding of what scope.$eval(attrs.ngFileInputChange)
is actually doing, so maybe I could make some change in that?
EDIT:
I should also add that I need access to some scope variables. For example, if I didn't have to use the custom directive, I would write something like this in my controller:
vm.base64Test(associatedData){
console.log(associatedData);
}
And then:
<input ng-change("vm.base64Test(vm.associatedData)">
But ng-change doesn't watch file input contents and the custom directive doesn't allow arguments (other than event), so I'm stuck.
Firstly, if you're planning on calling a method from a directive's API (so to speak), you need to identify it as a callback:
scope: {
'onChange': '&ngFileInputChange'
}
This simply means you're defined/exposing a way to declare a callback when the scope.onChange
gets triggered. It also means you don't need to $parse
or $eval
since the isolate scope can handle that for you.
Next you can trigger that callback much like you're already doing:
element.bind('change', function(evt){
$scope.$apply(function(){
var payload = { $data:<whatever-you-pull-from-your-file-change-evt> }
$scope.onChange(payload)
})
});
One thing to note is that I'm calling the callback within the $scope.$apply
. Because you're listening on non-angular events (e.g. onChange), you need to notify angular a change has occurred outside of the $digest
cycle.
Where you've declared your directive, in your actual callback (probably defined on your view controller) you can pass the payload to the method like so:
<input ng-file-input-change="vm.doSomething($data)">
When passing a function to a directive you usually need to pass the function pointer, so the directive can call the function later with arbitrary arguments.
In this case, your directive is evaluating the attribute to a function pointer (that's what the $eval is doing), and then binding it as a change
handler to the element the directive is attached to. You don't need (or want) to have parenthesis.
There's nothing wrong with your code as it is currently. I have a directive which does the exact same thing, it works great! (and when your function vm.base64Test
is called you will get the standard arguments for a change event on an input.) So you can have vm.base64Test
be:
function(event) {
console.log(event);
// your other code here
// event.target will give you the input element the code was called on
// event.target.files will give you an array of the files selected by the user
}