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?
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.
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.
14) Which of the following is used to share data between controller and view in AngularJS? Answer: B: "using services" is the correct answer.
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.
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;
});
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With