81

I am trying to do some validation on file change. Here is my code:

View/Template

<input type="file" name="file" id="file"  
       onchange="angular.element(this).scope().setFile(this)" 
       required />

<span class="error" ng-show="myForm.file.$error.required">Error</span>
<span class="error" ng-show="myForm.file.$error.size">Selected file is too large</span>
<span class="error" ng-show="myForm.file.$error.filetype">Unsupported File type</span>

Controller

angular.module("myapp").controller("myctrl", function($scope) {
  $scope.setFile = function(element) {
    $scope.$apply(function($scope) {
      var fileObject = element.files[0];
      $scope.file.fileType = 
         fileObject.type.toUpperCase().substring(fileObject.type.indexOf("/") + 1);

      // Validation
      if (!$scope.isValidFileType($scope.file.fileType)) {
        myForm.file.$setValidity("myForm.file.$error.filetype", false);
      }

      if (fileObject.size > 1000*1000*10) {
        myForm.file.$setValidity("myForm.file.$error.size", false);
      }
    });
  };

  $scope.isValidFileType = function(fileExtension) {
    var supportedExtensions = ["doc", "docx", "ppt", "pptx", "jpg", "gif", "png"]; // etc.
    return (jQuery.inArray(fileExtension, supportedExtensions) > -1);
  }
});

But right now the call to $setValidity is not working.
Any thoughts?

Dr1Ku
  • 2,875
  • 3
  • 47
  • 56
Churk
  • 4,556
  • 5
  • 22
  • 37

3 Answers3

131

This line:

myForm.file.$setValidity("myForm.file.$error.size", false);

Should be

$scope.myForm.file.$setValidity("size", false);
Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
17

$setValidity needs to be called on the ngModelController. Inside the controller, I think that means $scope.myForm.file.$setValidity().

See also section "Custom Validation" on the Forms page, if you haven't already.

Also, for the first argument to $setValidity, use just 'filetype' and 'size'.

Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • Actually, what you guys pointed out was correct, i did made a mistake in setValidity(). But that wasn't where my problem was, my problem was scoping issue. I was calling this at the level while form is out of scope. I actually had to do this: `$scope.$on('$includeContentLoaded', function(e) { $scope.myForm = e.targetScope.myForm;});` – Churk Jan 22 '13 at 19:44
2

A better and optimised solution to display multiple validation messages for a single element would be like this.

<div ng-messages="myForm.file.$error" ng-show="myForm.file.$touched">
 <span class="error" ng-message="required"> <your message> </span>
 <span class="error" ng-message="size"> <your message> </span>
 <span class="error" ng-message="filetype"> <your message> </span>
</div>

Controller Code should be the one suggested by @ Ben Lesh

Alex Mac
  • 2,970
  • 1
  • 22
  • 39
Alvin Chettiar
  • 609
  • 5
  • 14