[angularjs] Can I access a form in the controller?

I'm currently using the following.

$scope.$$childHead.customerForm[firstName], so that:

<form name="customerForm">
  <input type="text" name="firstName" 
         ng-model="data.customer.firstName" 
         tabindex="1"  
         ng-disabled="!data.editable" 
         validationcustomer />
</form>

But this only works in Chrome. Now I tried the following:

$scope.editCustomerForm[firstName], so that:

<form name="customerForm" ng-model="editCustomerForm">
  <input type="text" name="firstName" 
         ng-model="data.customer.firstName" tabindex="1"  
         ng-disabled="!data.editable" 
         validationcustomer />
</form>

Which doesn't work. Note my form is inside a Foundation Tab. How can I access firstName?

EDIT: It looks like the form isn't added to the scope when it's inside a Foundation Tab.

Anyone has got a solution for this?

This question is related to angularjs angular-foundation angularjs-forms

The answer is


This answer is a little late, but I stumbled upon a solution that makes everything a LOT easier.

You can actually assign the form name directly to your controller if you're using the controllerAs syntax and then reference it from your "this" variable. Here's how I did it in my code:

I configured the controller via ui-router (but you can do it however you want, even in the HTML directly with something like <div ng-controller="someController as myCtrl">) This is what it might look like in a ui-router configuration:

views: {
            "": {
                templateUrl: "someTemplate.html",
                controller: "someController",
                controllerAs: "myCtrl"
            }
       }

and then in the HTML, you just set the form name as the "controllerAs"."name" like so:

<ng-form name="myCtrl.someForm">
    <!-- example form code here -->
    <input name="firstName" ng-model="myCtrl.user.firstName" required>
</ng-form>

now inside your controller you can very simply do this:

angular
.module("something")
.controller("someController",
    [
       "$scope",
        function ($scope) {
            var vm = this;
            if(vm.someForm.$valid){
              // do something
            }
    }]);

Yes, you can access a form in the controller (as stated in the docs).

Except when your form is not defined in the controller scope and is defined in a child scope instead.

Basically, some angular directives, such as ng-if, ng-repeat or ng-include, will create an isolated child scope. So will any custom directives with a scope: {} property defined. Probably, your foundation components are also in your way.

I had the same problem when introducing a simple ng-if around the <form> tag.

See these for more info:

Note: I suggest you re-write your question. The answer to your question is yes but your problem is slightly different:

Can I access a form in a child scope from the controller?

To which the answer would simply be: no.


You can attach the form to some object which is defined in a parent controller. Then you can reach your form even from a child scope.

Parent controller

$scope.forms = {};

Some template in a child scope

<form name="forms.form1">
</form>

Problem is that the form doesn't have to be defined in the moment when to code in the controller is executed. So you have to do something like this

$scope.$watch('forms.form1', function(form) {
  if(form) {
    // your code...
  }
});

To be able to access the form in your controller, you have to add it to a dummy scope object.

Something like $scope.dummy = {}

For your situation this would mean something like:

<form name="dummy.customerForm">

In your controller you will be able to access the form by:

$scope.dummy.customerForm

and you will be able to do stuff like

$scope.dummy.customerForm.$setPristine()

WIKI LINK

Having a '.' in your models will ensure that prototypal inheritance is in play. So, use <input type="text" ng-model="someObj.prop1"> rather than <input type="text" ng-model="prop1">

If you really want/need to use a primitive, there are two workarounds:

1.Use $parent.parentScopeProperty in the child scope. This will prevent the child scope from creating its own property. 2.Define a function on the parent scope, and call it from the child, passing the primitive value up to the parent (not always possible)


If you want to pass the form to the controller for validation purposes you can simply pass it as an argument to the method handling the submission. Use the form name, so for the original question it would be something like:

<button ng-click="submit(customerForm)">Save</button>

Though alluded to in other comments I thought I'd spell it out a bit for those using the "Controller As" syntax:

<div ng-controller="MyController as ctrl">

<form name="ctrl.myForm">
    ...inputs
    Dirty? {{ctrl.myForm.$dirty}}

    <button ng-click="ctrl.saveChanges()">Save</button>
</form>

</div>

Then you can access the FormController in your code like:

function MyController () {
    var vm = this;
    vm.saveChanges = saveChanges;

    function saveChanges() {

       if(vm.myForm.$valid) { 
            // Save to db or whatever.
            vm.myForm.$setPristine();
       }
}

Bit late for an answer but came with following option. It is working for me but not sure if it is the correct way or not.

In my view I'm doing this:

<form name="formName">
    <div ng-init="setForm(formName);"></div>
</form>

And in the controller:

$scope.setForm = function (form) {
    $scope.myForm = form;
}

Now after doing this I have got my form in my controller variable which is $scope.myForm


Definitely you can't access form in scope bec. it is not created. The DOM from html template is loaded little bit slowly like controller constructor. the solution is to watch until DOM loaded and all the scope defined!

in controller:

$timeout(function(){
    console.log('customerForm:', $scope.customerForm);
    // everything else what you need
});

add ng-model="$ctrl.formName" attribute to your form, and then in the controller you can access the form as an object inside your controller by this.formName