Simple AngularJS Form is undefined in Scope

FormsAngularjs

Forms Problem Overview


I'm starting to play around with AngularJS forms in jsfiddle and I've come across a problem already where a very simple form example is not working as expected. All I have is a named form and it's not showing up in scope for some reason (I'm expecting a FormController instance).

I have a fiddle set up, and below is the basic code:

HTML

<div id="mainContainer" ng-app="angularTest" ng-controller="MainCtrl">
    <h1>The Form</h1>
    <form name="theForm">
        <input name="myName" type="text" ng-model="model.name" />
        <input name="submit" type="submit" />
    </form>
</div>

JS

var app = angular.module('angularTest', []);

app.controller('MainCtrl', ['$scope', function($scope) {
    $scope.model = { name: 'Model Name' };
    console.log($scope.theForm); //displays 'undefined'
}]);

I can't find a lot of straightforward examples of this on jsfiddle, so I wasn't sure if this could be some strange interaction with sites like it (most examples I find aren't using formal controllers). I've tried on Plunker to check as well, but I encounter the same problem.

I'm sure I'm missing something super obvious, but I can't see many other things to change or tweak here. Any help is greatly appreciated!

Forms Solutions


Solution 1 - Forms

A good way to perform this without using watch (which is a bit overkill) is to define an object in the scope into which you will register the form.

HTML

<div id="mainContainer" ng-app="angularTest" ng-controller="MainCtrl">
    <h1>The Form</h1>
    <form name="form.theForm">
        <input name="myName" type="text" ng-model="model.name" />
        <input type="button" value="Here the scope" ng-click="display()"/>
        <input name="submit" type="submit" />
    </form>
</div>

JS

var app = angular.module('angularTest', []);

app.controller('MainCtrl', ['$scope', function($scope) {
    $scope.model = { name: 'Model Name' };
    $scope.form = {};
    $scope.display = function () {
        console.log($scope.form.theForm);
    }
}]);

Solution 2 - Forms

The form only registers itself with the $scope of the controller after the controller has initially run. Therefore the console.log($scope.theForm) will return undefined even if everything is setup correctly.

In your example to react to the presence of theForm, you can setup a watcher on theForm to set debug text depending its presence:

$scope.$watch('theForm', function(theForm) {
    if(theForm) { 
        $scope.formDebugText = 'Form in Scope';
    }
    else {
        $scope.formDebugText = 'Form is Undefined';
    }        
});

which can be seen in action at http://jsfiddle.net/9k2Jk/1/

Solution 3 - Forms

What fixed it for me was to use a parent object on the $scope.

In the controller:

$scope.forms = {};
$scope.registerUser = function registerUser() {
    if ($scope.forms.userForm.$valid) {
        alert('submit');
    }
};

In the template:

<form name="forms.userForm" ng-submit="registerUser()">

The reason:

If you use <form name="userForm"... instead of <form name="forms.userForm"... it attaches the form to a child scope, but because $scopes use prototypical inheritance, as soon as I declared an empty object literal on the original $scope the form was attached to it instead.

Solution 4 - Forms

This is the recommended way to access form variable: https://docs.angularjs.org/guide/forms - Binding to form and control state

In HTML:

<form name="form">  
<input type="button" ng-click="reset(form)" value="Reset" />
</form>

Youl will pass the name of the form as a variable to the function.

In JS :

$scope.reset = function(form) { 
  alert(form); 
};

Variable 'form' should NOT be undefined now.

Solution 5 - Forms

In my case I used ng-include to generate a sub scope, so within current scope the property is undefined, to be safe and prevent sub-scope issue, we should use reversed variable to name the form just like form.theForm.

But make sure that you've declared this form name in your controller in advance.

<form name="form.theForm">
    <input name="myName" type="text" ng-model="model.name" />
    <input name="submit" type="submit" />
</form>

app.controller('MainCtrl', ['$scope', function($scope) {
    $scope.model = { name: 'Model Name' };
    //You have to declare here, else it will trigger undefined error still.
    $scope.form = {
      theForm: {} 
    };

    $scope.reset = function(){
       $scope.form.theForm.$setPristine();
    }
}]);

Solution 6 - Forms

You can re-initialize the form from your controller before you try to access $scope.form with this line of code. $scope.form will then be available.

angular.element(jQuery('.form-control')).triggerHandler('input')

Solution 7 - Forms

I wrote a directive to deal with this issue. Its an attribute that you can put on your form and pass a function to which will execute when the form is ready.

Javascript

angular.module('app').directive('formInit', function(){
  return {
    restrict: 'A',
    scope: {
      init: '&formInit'
    },
    controller: function($scope, $element){
      var name = null;
      if ($element[0] && $element[0].name){
        name = $element[0].name;
      }

      var listener = $scope.$watch('init', function(){
        if ($scope[name] && $scope.init){
          $scope.init();
          listener();
        }
      });
    }
  };
});

Example HTML

<form name="test" form-init="testing()">

Where testing is a function on your controllers scope.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionchucknelsonView Question on Stackoverflow
Solution 1 - FormsIxDayView Answer on Stackoverflow
Solution 2 - FormsMichal CharemzaView Answer on Stackoverflow
Solution 3 - FormshofnarwillieView Answer on Stackoverflow
Solution 4 - FormsbogdanmatraView Answer on Stackoverflow
Solution 5 - FormsSaorikidoView Answer on Stackoverflow
Solution 6 - FormsBen WarrenView Answer on Stackoverflow
Solution 7 - FormsSimon TrewhellaView Answer on Stackoverflow