Issue
Trying to bind a custom onchange handler to the input file element. getting the following error:
Referencing DOM nodes in Angular expressions is disallowed! Expression: setRuleFile(element
Is there any way to work around it?
Thanks. Here are the relevant excerpts from my code.
html:
<input type="file" on-select-file="setRuleFile(element)"/>
controller:
$scope.setRuleFile = function(element) {
// Extract selected file name
var pathArray = element.value.split('\\');
$scope.data.ruleFileName = pathArray[pathArray.length - 1]; // take only name without path
$scope.data.ruleFile = element;
}
directive:
angular.module('myModule').directive('onSelectFile', function ($parse) {
// Triggered when user selects file
return {
restrict: 'A',
link: function (scope, element, attrs) {
// Get callback into variable and bind it to onchange handler
onSelectFileFunc = $parse(attrs.onSelectFile);
//console.log(onSelectFileFunc(scope, {'element': element}));
element.bind('change', function() { onSelectFileFunc(scope, {'element': element}); } );
}
};
})
Solution
Here is an example of how to write a file upload directive in Angular 1.x:
angular.module('myApp', [])
.directive('fileUpload', fileUploadDirective);
function fileUploadDirective() {
function postLink(scope, iElem, iAttrs) {
iElem.on('change', doStuff);
// remove DOM event listener when Angular scope is destroyed
scope.$on('$destroy', function() {
iElem.off('change', doStuff);
});
function doStuff() {
console.log(iElem[0].files);
};
};
return {
link: postLink,
restrict: 'A'
};
}
...and you would use it in your HTML template like this:
<input type="file" file-upload>
JSFiddle: https://jsfiddle.net/sscovil/o0ysyem5/
This directive just uses jqLite (Angular's watered-down version of jQuery) to add a DOM event listener to the element; and the HTML5 File API to get the file object from the element.
Update
Per the OP's comment, the following is an updated example that shows how to make the file object available to other directives in the same scope.
angular.module('myApp', [])
.directive('fileUpload', fileUploadDirective);
function fileUploadDirective() {
var postLink = function(scope, iElem, iAttrs, ngModelController) {
function updateModel(event) {
if (iElem[0].files && iElem[0].files.length) {
var file = iElem[0].files[0];
ngModelController.$setViewValue(file, event.type);
}
};
iElem.on('change', updateModel);
scope.$on('$destroy', function() {
iElem.off('change', updateModel);
});
};
return {
link: postLink,
require: 'ngModel',
restrict: 'A'
};
}
...and you would use it in your HTML template like this:
<input type="file" ng-model="myFile" file-upload>
JSFiddle: https://jsfiddle.net/sscovil/o0ysyem5/3/
This example uses ngModelController, rather than binding the file directly to scope. Doing so enables the user of the directive to decide which variable to store the file object in, via the ng-model
attribute.
Answered By - Shaun Scovil
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.