88

I need to check if a form is valid in a controller.

View:

<form novalidate=""
      name="createBusinessForm"
      ng-submit="setBusinessInformation()"
      class="css-form">
 <!-- fields -->
</form>

In my controller:

.controller(
    'BusinessCtrl',
    function ($scope, $http, $location, Business, BusinessService, 
              UserService, Photo)
    {

        if ($scope.createBusinessForm.$valid) {
            $scope.informationStatus = true;
        }

        ...

I'm getting this error:

TypeError: Cannot read property '$valid' of undefined
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
Rober
  • 5,868
  • 17
  • 58
  • 110
  • Did you wrap it around the setBusinessInformation function within the controller? – matsko Nov 18 '13 at 17:39
  • 3
    code too fragmented to analyze what could be wrong...create a simple demo in jsfiddle.net or plunker that replicates problem. Is form within scope of `BusinessCtrl`? can't tell without seeing more – charlietfl Nov 18 '13 at 17:45
  • @matsko: No. I need to execute this code on controller initialization. – Rober Nov 18 '13 at 18:53
  • @charlietfl: There is not much more. I remove some code in order to simplify the example. Yes, the form should be in the scope of BusinessCtrl (the controller is set on routes in app.js. I add my solution in an answer below. But, I don´t know why is not working this way. – Rober Nov 18 '13 at 18:55

5 Answers5

111

Try this

in view:

<form name="formName" ng-submit="submitForm(formName)">
 <!-- fields -->
</form>

in controller:

$scope.submitForm = function(form){
  if(form.$valid) {
   // Code here if valid
  }
};

or

in view:

<form name="formName" ng-submit="submitForm(formName.$valid)">
  <!-- fields -->
</form>

in controller:

$scope.submitForm = function(formValid){
  if(formValid) {
    // Code here if valid
  }
};
Damsorian
  • 1,664
  • 2
  • 14
  • 10
  • What if I want to validate multiple buttons in a form? – Fahad Mullaji Mar 11 '15 at 00:36
  • this worked for me, but why `$scope.formName.$valid` results in undefined? – ps0604 Jan 24 '16 at 00:54
  • If you use ng-if then $scope.formName.$valid will not work and if you use ng-show then $scope.formName.$valid will work. – Vaibhav Shaha Mar 04 '16 at 13:17
  • 2
    This should be the best answer, simple. But could you handle the form invalid ? How could you show to user what inputs are invalid ? – Nicolas Leucci Sep 22 '16 at 15:00
  • 1
    @ps0604 the `formName.$valid` can be accessed only in the template, if you want to access in the controller you need to create an object for that like `$scope.forms.formName` and in the template: `
    ` [check this comment](http://stackoverflow.com/a/27013197/3971521)
    – Damsorian Sep 23 '16 at 19:16
  • @NicolasLeucci you have `formName.inputName.$valid` for that. you can check the [input documentation](https://docs.angularjs.org/api/ng/directive/input) – Damsorian Sep 23 '16 at 19:19
  • @FahadMullaji the same as `NicolasLeucci` you need to check the [input documentation](https://docs.angularjs.org/api/ng/directive/input) – Damsorian Sep 23 '16 at 19:20
  • NIce clean answer. – dewd Oct 31 '17 at 17:48
29

I have updated the controller to:

.controller('BusinessCtrl',
    function ($scope, $http, $location, Business, BusinessService, UserService, Photo) {
        $scope.$watch('createBusinessForm.$valid', function(newVal) {
            //$scope.valid = newVal;
            $scope.informationStatus = true;
        });
        ...
Alan Dunning
  • 1,341
  • 8
  • 17
Rober
  • 5,868
  • 17
  • 58
  • 110
  • Also remember that - If the form is a Modal then remember to declare form name as dot notation eg: "data.theform" and access it in your controller as $scope.data.theform – Jasper Oct 04 '14 at 14:32
  • 2
    This does not work for me. Please show how you get 'createBusinessForm' into the controller's $scope. – cyrf Feb 02 '16 at 13:40
  • $scope things has gone, now a days we are using `vm` approach. can you create a plunker for same answer by using controller as syntax approach. I am not able to do it. It will be helpful for other as well who are looking for answer with today's context. Thanks – ankitd Oct 02 '16 at 05:21
14

Here is another solution

Set a hidden scope variable in your html then you can use it from your controller:

<span style="display:none" >{{ formValid = myForm.$valid}}</span>

Here is the full working example:

angular.module('App', [])
.controller('myController', function($scope) {
  $scope.userType = 'guest';
  $scope.formValid = false;
  console.info('Ctrl init, no form.');
  
  $scope.$watch('myForm', function() {
    console.info('myForm watch');
    console.log($scope.formValid);
  });
  
  $scope.isFormValid = function() {
    //test the new scope variable
    console.log('form valid?: ', $scope.formValid);
  };
});
<!doctype html>
<html ng-app="App">
<head>
 <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js"></script>
</head>
<body>

<form name="myForm" ng-controller="myController">
  userType: <input name="input" ng-model="userType" required>
  <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
  <tt>userType = {{userType}}</tt><br>
  <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br>
  <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br>
  <tt>myForm.$valid = {{myForm.$valid}}</tt><br>
  <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br>
  
  
  /*-- Hidden Variable formValid to use in your controller --*/
  <span style="display:none" >{{ formValid = myForm.$valid}}</span>
  
  
  <br/>
  <button ng-click="isFormValid()">Check Valid</button>
 </form>
</body>
</html>
Biswas Khayargoli
  • 976
  • 1
  • 11
  • 29
Enkode
  • 4,515
  • 4
  • 35
  • 50
4

The BusinessCtrl is initialised before the createBusinessForm's FormController. Even if you have the ngController on the form won't work the way you wanted. You can't help this (you can create your ngControllerDirective, and try to trick the priority.) this is how angularjs works.

See this plnkr for example: http://plnkr.co/edit/WYyu3raWQHkJ7XQzpDtY?p=preview

Oliver
  • 4,471
  • 2
  • 21
  • 18
0

I like to disable the save/submit button if the form is invalid:

<form name="ruleForm">
    <md-input-container>
        <label>Priority</span>
        <input name="description" ng-model="vm.record.description" required>
    </md-input-container>
    <md-button ng-click="vm.save()" ng-disabled="ruleForm.$invalid" class="md-primary md-raised">Save</md-button>
</form>
Todd Hale
  • 480
  • 8
  • 15