0

I'm fairly new to Angular and I'm facing difficulties in communicating between parent and child controllers.

The jsfiddle is here - http://jsfiddle.net/NEuJ6/35/

What I'm doing is loading a form template based on a route with a new controller. The parent controller however has the "Save and Continue" button and I'm not able to understand on how to bind the changes in the form of the child (valid / invalid state) to the button disabled status of the parent.

In short, the problem is getting the live state of the form that lives in the child controller in the parent controller

I believe, this can be solved via a $watch, but I'm not sure how to proceed.

Controller

<div ng-controller="MainCtrl">
  <ul>
    <li><a href="#/new">New User</a></li>
    <li><a href="#/edit">Edit USer</a></li>
    <li>To continue as guest, click on submit</li>
  </ul>
  <ng-view></ng-view>
    <button ng-click="save()">Save and continue</button>
</div>

Routes

app.config( function ( $routeProvider ) {
  $routeProvider
  .when('/edit', {
      templateUrl: "form.html", 
      controller: "EditController"
  })
  .when('/new', {
      templateUrl: "form.html",
      controller: "NewController"
  })
});

The second question is around loading the next step of the process. When the user clicks submit and the form is valid, in that case, I would like to change the ng-view with a new template. Is something like below recommended (in the controller)?

if (form.$valid) {
   location.path('/next')
}

or should I make the continue button an a tag and do something like

<a href="#/next" ng-click="validate()">Save and continue</a>

In both the cases, I will have a new route added.

 .when('/next', {
          templateUrl: "next.html", 
          controller: "NextController"
  })
Prakhar
  • 3,486
  • 17
  • 44
  • 61

2 Answers2

2

There is no built-in way to easily access the state of a child-controller from the parent-controller. Nor is it a good practice - the parent-controller should not care what child-controller it has.

The other way around is easy though and this is probably the easiest and cleanest approach:

  1. Have your parent-controller define a property, based on which it enables/disables the button.
  2. Have any child-controllers modify that property according to their internal state (e.g. a form's validity status).
    Note that in order for the child-controller to prototypally inherit the property and not overwrite it locally, it needs to not be a primitive (more info here).

E.g.:

/* In parent-controller */
$scope.buttonConfig = {enabled: false};

/* In child-controller */
$scope.$watch('form.$valid', function (newValue) {
    $scope.buttonConfig.enabled = !!newValue;
});

See, also, this modified demo.


Note:
There are other alternatives as well (e.g. using the $rootScope to store app-wide state, using a service to share data across controllers, use scope-messaging ($scope.$emit(), $scope.$on()) etc).

gkalpak
  • 47,844
  • 8
  • 105
  • 118
1

If you want to communicate between controllers then I think the recommended way would be with a service.

The service is injected into both the parent and the child controllers then effectively the child can call the setter method of the service to store the data in the service and the parent can be hooked up to a getter method on the service to retrieve the data.

You don't need to go to the extent of creating the service you could use a value provider.

The benefit of this pattern is that you reduce the coupling between the two controllers they don't depend on each other or shared knowledge they only know that they should have a service which gives them the information from the child or they should have a service where they have to put the data.

Please the angular docs on providers for example implementations https://docs.angularjs.org/guide/providers

Your question is closely related to / duplicate of this question

What's the correct way to communicate between controllers in AngularJS?

The initial answers revolve around using the eventing model in angular - broadcast/emit and while the problems with this pattern are resolved in current versions of angular I would still have to agree with those who prefer the service based solution.

Community
  • 1
  • 1
Hargrovm
  • 1,053
  • 8
  • 10
  • That makes sense. I have a factory already in placing for sharing some data. However, I was under the assumption that the parent and child relationship might make it easier. Also, in case I build a service, how will I get / set the status of form valid / invalid status? Any pointers in that direction? – Prakhar Jun 30 '14 at 20:55
  • I think your save and continue buttons are in the wrong place they need to be hooked up to the child controller it's the child controller then that is responsible for deciding if the contents it has is ok or not, what happens on submit etc. your shared data service then effectively becomes your persistence service and everything gets more straightforward. To answer the second part of your question - either could work its a matter of preference I think. – Hargrovm Jun 30 '14 at 21:20
  • 1
    @Prakhar, Hargrovm: I think people tend to confuse `data` with `state` or even with `any JS variable`. Services are indeed good for sharing `data`, but a button's state or a form's validity is not `data`. Although services are a viable alternative, I think there are better ways for sharing state. Just my 2 cents... – gkalpak Jun 30 '14 at 21:33
  • Thanks a lot for comment ExpertSystem! I just started out Ng and getting this difference clear at this stage is great! Thanks! – Prakhar Jul 01 '14 at 04:58