24

HTML:

<form name="form">
    <input type="file" ng-model="document" valid-file required>
    <input type="submit" value="{{ !form.$valid && 'invalid' || 'valid' }}">
</form>

Custom directive to listen for input[type=file] changes:

myApp.directive('validFile',function(){
    return {
        require:'ngModel',
        link:function(scope,el,attrs,ngModel){

            //change event is fired when file is selected
            el.bind('change',function(){
                 scope.$apply(function(){
                     ngModel.$setViewValue(el.val());
                     ngModel.$render();
                 });
            });
        }
    };
});

When file is selected following error appears in console:

Error: InvalidStateError: DOM Exception 11 Error: An attempt was made to use an object that is not, or is no longer, usable.

Try with plunkr: http://plnkr.co/edit/C5j5e0JyMjt9vUopLDHc?p=preview

Without the directive the the state of the input file field wont be pushed to form.$valid. Any ideas why I get this error and how to fix this?

2 Answers 2

29

From the reference of NgModelController.$render()

Called when the view needs to be updated. It is expected that the user of the ng-model directive will implement this method.

You need to implement $render() to call it. You can do something like this

myApp.directive('validFile', function () {
    return {
        require: 'ngModel',
        link: function (scope, el, attrs, ngModel) {
            ngModel.$render = function () {
                ngModel.$setViewValue(el.val());
            };

            el.bind('change', function () {
                scope.$apply(function () {
                    ngModel.$render();
                });
            });
        }
    };
});

DEMO

Sign up to request clarification or add additional context in comments.

1 Comment

is it possible to get the file size inside the renderer? e.g. to check the mimetype or size of the file that has been selected ...
4

After updating to AngularJS 1.2.x the snippet looks not working properly anymore and the file input doesn't sticks with the selected file value, making the form unusable. Changing the directive back to your original one, and removing the ngModel.$render() it looks working like a charm:

.directive('validFile', function () {
  return {
    restrict: 'A',
    require: '?ngModel',
    link: function (scope, el, attrs, ngModel) {
      el.bind('change', function () {
        scope.$apply(function () {
          ngModel.$setViewValue(el.val());
        });
      });
    }
  };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.