2

I am trying do understand why my form is not recognize inside the maincontroller, if I put another controller outside, my form is recognize.

config.js

var myApp = angular.module('Myapp', ['ui.router','oc.lazyLoad','ui.bootstrap','kendo.directives','ngStorage',]);

function config($stateProvider, $urlRouterProvider, $ocLazyLoadProvider) {
    $urlRouterProvider.otherwise("/index/main");
    $stateProvider
        .state('testing', {
            url: "/testing",
            controller: 'MyController',
            templateUrl: "testing.html"
        });
}

angular
    .module('Myapp')
    .config(config)
    .run(function($rootScope, $state) {
        $rootScope.$state = $state;
    }); 

MyController.js

function MyController($scope) {     
  //do something
  $scope.test = {name: 'das'};

    $scope.sendTest = function () {
        console.log($scope.form.$valid);
        console.log($scope.form.testNumber.$valid);
        console.log($scope.form.testName.$valid);
    };
};

angular
    .module('Myapp')
    .controller('MyController', ["$scope"]);

testing.html

<form name="form" novalidate>
    <p>
        <label>Number: </label>
        <input type="number" min="0" max="10" ng-model="test.number" name="testNumber" required />
    </p>
    <p>
        <label>Name: </label>
        <input type="text" ng-model="test.name" name="testName" required />
    </p>
    <button ng-click="sendTest()">Submit</button>
</form> 

Like this a have this error

TypeError: Cannot read property '$valid' of undefined

but if I create another controller inside MyController.js and i move the code inside like this

function ChildController($scope,$timeout) {
    $scope.test = {
        name: 'das'
    };

    $scope.sendTest = function () {
        console.log($scope.form.$valid);
        console.log($scope.form.testNumber.$valid);
        console.log($scope.form.testName.$valid);
    };
};

function MyController($scope) {  //do other stuff ...};


angular
    .module('Myapp')
    .controller('ChildController', ["$scope", ChildController])
    .controller('MyController', ["$scope"]);

and add the ng-controller to the form like this

<form name="form" novalidate ng-controller='ChildController'>

the form is reconize correctly and working.

Can anyone explain what I am missing here, i would like to understand better, I am a novice.

Thanks you for the help.

Best regards. Jolynice

jolynice
  • 514
  • 1
  • 8
  • 25
  • Did you put ```ng-controller='MyController'```anywhere ? – Komo Nov 18 '15 at 15:41
  • Looks like its bound via the route. – Sean Larkin Nov 18 '15 at 15:43
  • Hello Komo and Sean. I don´t have ng-controller = 'MyController', the declaration is only in route controller: 'MyController', – jolynice Nov 18 '15 at 15:46
  • The form's getting created on a child scope (not your controller's scope). The easiest way to fix would be to move to the "Controller As" syntax, but another way would be to create an empty vm on your scope - `$scope.forms = {};` and then reference a child of that from your markup: `ng-form="forms.form"` – Brad Barber Nov 18 '15 at 15:50
  • first of all let me express my gratitude for all the help i am receiving, is my first post, and i was not expecting so quickly answers. Thanks you all. – jolynice Nov 18 '15 at 15:54

2 Answers2

1

As seen in Brad Barber's comment:

The form is being created on the child scope and not the controller scope.

A good solution like he suggested would be to add the bindToController and controllerAs syntax to your route object:

function config($stateProvider, $urlRouterProvider, $ocLazyLoadProvider) {
    $urlRouterProvider.otherwise("/index/main");
    $stateProvider
        .state('testing', {
            url: "/testing",
            controller: 'MyController',
            controllerAs: 'viewCtrl',
            bindToController: 'true',
            templateUrl: "testing.html"
        });
}

Now you can bind the name of the form as viewCtrl.form:

<form name="viewCtrl.form" novalidate>
    <p>
        <label>Number: </label>
        <input type="number" min="0" max="10" ng-model="viewCtrl.test.number" name="testNumber" required />
    </p>
    <p>
        <label>Name: </label>
        <input type="text" ng-model="viewCtrl.test.name" name="testName" required />
    </p>
    <button ng-click="viewCtrl.sendTest()">Submit</button>
</form> 

You can then notate it in your controller using this:

function MyController($scope) {     
  // Adding variables functions available to ctrl scope
  // same as vm = this;
  angular.extend(this, {
    test: {name: 'das'},
    sendTest: function() {
       console.log(this.form.$valid);
       console.log(this.form.testNumber.$valid);
       console.log(this.form.testName.$valid);
    }
  });

};

angular
    .module('Myapp')
    .controller('MyController', ["$scope", MyController]);

Here is a codepen that I hacked together for you:

Sean Larkin
  • 6,290
  • 1
  • 28
  • 43
  • Hi Sean, thank for your anwser, but i think i am missing something, I´ve done like you said, but nothing appens. no error .. nada .. lol , if is not to much to ask, can you create an example? – jolynice Nov 18 '15 at 16:38
  • I'll attempt to, I have never do so before with ui-router in it. Give me a few moments. – Sean Larkin Nov 18 '15 at 16:51
  • I made a few changes to the code as there were some syntax issues. This should correspond to the codepen. – Sean Larkin Nov 18 '15 at 17:06
  • Thank you Sean, working well and now I understand. 5 stars ;) – jolynice Nov 18 '15 at 17:17
1

Check whether if the form is inside any div which has ng-if condition Like

<div ng-if="condition">
  <form name="viewCtrl.form">
   .
  </form>
</div>

If this is so, the form would return undefined since there is new scope created for the DOM containing ng-if condition. Then use ng-show instead of ng-if that would not create new scope. I got this solution from this answer