I'm trying to create a directive with angularjs but I found a problem.
Here is the js code of the directive
angular.module('xxxFileUploader', [])
.directive('xxxFileUploader', function() {
return {
restrict: 'E',
templateUrl: 'fileUploader.html',
scope: {
onChange: '='
},
link: function(scope, element, attrs) {
element.find('input[type="file"]').change(function() {
var input = this;
if (input.files && input.files[0]) {
scope.file = input.files[0];
scope.onChange(input.files[0]);
});
}
};
});
the directive template
<span style="position:relative;">
<a class='btn btn-primary' href='javascript:;'>
Choose File...
</a>
<input type="file"
name="{{field.name}}"
style='position:absolute;z-index:2;top:0;left:0;filter: alpha(opacity=0);opacity:0;background-color:transparent;color:transparent;'
/>
<span class='label label-info'>{{file.name}}</span>
</span>
a piece of html file where I use the directive
<xxx-file-uploader on-change="loadFile(field.name)" ></xxx-file-uploader>
and the relevant piece of my controller
$scope.loadFile = function(fieldName) {
return function(file) {
// do things with both fieldName and file...
};
};
This code should just customize the look of an input of type file and execute a callback when a file is uploaded.
My problem comes from the fact that at the moment I need to use a change callback that is built dynamically for every fileUploader. As you can see the callback is built with a parameter fieldName that is known at link-time and a parameter file that is known at "execution-time".
With this code I get the AngularJS “Error: 10 $digest() iterations reached. Aborting!” because (I think) the function is generated again and again and the digests don't match.
A poor-man solution would be to pass the fieldName as another scope variable. Another again would be maybe to pass the function as a string (@) and build the callback when I need it.
Any suggestion on how to make this directive work without changing its interface? I'm quite new to angularjs directives (this is my first one!) so if you see anything wrong in the code please point it out.
Thank you.
First edit:
I tried to change the scope of the directive as I've been suggested from
scope: {
onChange: '='
},
to
scope: {
onChange: '&'
},
and I changed the callback call from
scope.onChange(input.files[0]);
to
scope.onChange()(input.files[0]);
now it works but I'm not completely satisfied with the result.
It looks like a need to call the onChange function to get my "real" callback. Is there a way to have it executed implicitly in this case?
What I mean is that if I write
<xxx-file-uploader on-change="loadFile(field.name)" ></xxx-file-uploader>
it should understand to execute the function
if instead i write
<xxx-file-uploader on-change="doSomething" ></xxx-file-uploader>
it should recognize that doSomething is the "real" callback I want it to execute (with the file parameter).