Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I access FormController in parent controller or scope in AngularJS

I have a page with multiple forms and I only want to show one at a time. For this I separated each form into a section and using Bootstrap's accordion plugin I only allow one open section at a time.

My markup looks something like this:

<a ng-click="open_section('section1')">Section 1</a>

<div collapse="section1">
  <form name="section1Form">
  </form>
</div>

<a ng-click="open_section('section2')">Section 2</a>

<div collapse="section2">
  <form name="section2Form">
  </form>
</div>

Everything work just fine, I can navigate between the forms etc.

Because I don't want the user opening a section if the one they are currently editing contains validation errors, I tried checking in the open_section function if the form associated with it is valid or not.

I tried, but I could not. I could not access the FormController associated with the forms in the controller that is responsible for the page. For some reason, they are not getting published on the scope.

This is what I tried:

  • $scope.section1Form is undefined

  • tried with $scope.$watch('section1Form, function(){}), still undefined

  • tried adding the name of the form as a second parameter to open_section like so: open_section('section1', section1Form) but in the function the second argument is undefined.

Between the <form></form> tags, I have access to the FormController, but outside them I don't. Since the event is coming from outside the <form> (the closing, opening of the sections) I can't pass the FormController to my controller to check the validity of my forms.

Is there a way to get around this, or should I refactor my page?

I am using Angular 1.1.5 btw.

Also, checking with the AngularJS Batarang Chrome plugin, I can see that the forms get published as child scopes to the current scope.

EDIT: this is how the scope hierarchy looks for this app

 - root
 |
 ---current controller\'s scope
 |
 ----scope that contains the forms

Is this because I'm using ng-include? Is there no way to access those forms in a controller then?

like image 388
adamors Avatar asked Oct 02 '13 15:10

adamors


People also ask

How do you access child controller scope in parent controller?

In angular there is a scope variable called $parent (i.e. $scope. $parent). $parent is used to access parent scope from child controller in Angular JS.

What is parent scope in AngularJS?

Angular scopes include a variable called $parent (i.e. $scope. $parent ) that refer to the parent scope of a controller. If a controller is at the root of the application, the parent would be the root scope ( $rootScope ). Child controllers can therefore modify the parent scope since they access to it.

How do you share data between controller and view in AngularJS?

14) Which of the following is used to share data between controller and view in AngularJS? Answer: B: "using services" is the correct answer.

How does scope inheritance work in AngularJS?

Scope InheritanceIf we define nested controllers, then the child controller inherits the scope of its parent controller. We assign values to the models in shapeController. We override message in child controller named circleController.


2 Answers

To deal with dynamic forms, and thus the dynamic location of the associated FormController, I used a simple directive to help locate the scope that contains the form.

Solution:

Create a directive that $emit's the scope associated w/the form:

  module.directive('formLocator', function() {
    return {
      link: function(scope) {
        scope.$emit('formLocator');
      }
    }

Use the directive in the markup:

<form name="myForm" novalidate form-locator>

Listen for the event broadcast by the directive in your controller:

$scope.$on('formLocator', function(event) {
  $scope.myDeeplyNestedForm = event.targetScope.myForm;
});
like image 118
Sunil D. Avatar answered Oct 13 '22 19:10

Sunil D.


There a much simpler way to communicate back up in the scope hierarchy by using angular process of looking for objects up in its scope hierarchy.

This allows us to attach the object from a lower scope into a higher scope by using the dot notation.

In this case you need to create a "catcher" empty object on the top level controller. This catcher object can then be assigned the form objects from the lower scopes. Here is a plunk for demo.

http://plnkr.co/edit/xwsu48bjM3LofAoaRDsN?p=preview

It isn't perfectly elegant but if you think of this "catcher" object as an event listener, we're still following a standard pattern.

create an empty catcher object in the controller where you'd like a reference to the nested form

function mainController($scope){
  $scope.catcher = {

  };
 }

Then in the markup itself whenever the ng-form directive is declared, set catcher.formName = formName like so

<ng-form name="alpha">
          <span ng-init="catcher.alpha = alpha"></span>
          <input type="text" required="" ng-model="alphaValue" />
        </ng-form>

Because we're assigned to "catcher.", angular will traverse up the scope hierarchy and find thd it in the mainController regardless of any number of controllers in between (assuming they also don't have a catcher object, of course)

like image 22
Abhinav Gujjar Avatar answered Oct 13 '22 19:10

Abhinav Gujjar