Reputation: 2336
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!
Upvotes: 64
Views: 76793
Reputation: 2280
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();
}
}]);
Upvotes: 4
Reputation: 3707
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);
}
}]);
Upvotes: 90
Reputation: 11
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')
Upvotes: 1
Reputation: 3660
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.
Upvotes: 32
Reputation: 231
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.
Upvotes: 23
Reputation: 2484
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.
Upvotes: 0
Reputation: 27012
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/
Upvotes: 41