1

I have a directive that is replaced by a form. That form is bound to a vm.customer object.

Assuming this directive will be used in multiple parts of the application and each vm.customer object should have it's own scope, what are some ways that the parent controller can access its vm.customer object?

// Directive

(function() {

'use strict';

angular
    .module('rugapp')
    .directive('customer', customer);

    function customer() {
        return {
          scope: {
          },
          restrict: 'E',
          templateUrl: 'rugapp/directives/customer-directive.html',
          replace: true,
          controller: 'CustomerController',
          controllerAs: 'vm'
        };
    }

})();

// View

<div class="scrollable">
  <div class="scrollable-content section">
    <customer></customer>
  </div>
</div>

// Parent Controller

(function() {

'use strict';

angular
    .module('rugapp')
    .controller('CreateScheduleController', CreateScheduleController);

    function CreateScheduleController() {

        var vm = this;

        activate();

        function activate() {

        }

    }

})();
Raphael Rafatpanah
  • 19,082
  • 25
  • 92
  • 158

2 Answers2

1

The proper way to communicate between the directive and its parent controller is to use a directive's attribute.

In the directive, you can define a two-way binding attribute as following:

(function() {

'use strict';

angular
    .module('rugapp')
    .directive('customer', customer);

    function customer() {
        return {
          scope: {
              person: '='
          },
          restrict: 'E',
          templateUrl: 'rugapp/directives/customer-directive.html',
          replace: true,
          controller: 'CustomerController',
          controllerAs: 'vm',
          bindToController: true // Bind the person property to the vm controller instead of the scope
        };
    }

})();

Then, in your view, you pass a customer object as following:

<div class="scrollable">
  <div class="scrollable-content section">
    <customer person='vm.person'></customer>
  </div>
</div>

Finally, you can access this variable in your parent controller:

(function() {

'use strict';

angular
    .module('rugapp')
    .controller('CreateScheduleController', CreateScheduleController);

    function CreateScheduleController($scope) {

        var vm = this;

        activate();

        function activate() {
            console.log($scope.vm.person) // Do somethings with the person
        }

    }

})();
lvarayut
  • 13,963
  • 17
  • 63
  • 87
  • Please correct me if I'm wrong, but it seems like the parent controller is setting the person object here. What I am looking for is to get the person object from the directive into the parent controller. Is this still valid? – Raphael Rafatpanah Jan 20 '15 at 15:44
  • Yes, it's still valid because it's two-way binding. So, you can change the `$scope.person` either in the parent or in the directive. The value will be sync between them. You can read more about this in the [Angular directive](https://docs.angularjs.org/guide/directive), the Isolating the Scope of a Directive section. – lvarayut Jan 20 '15 at 15:48
  • Excellent, thank you. Is there anything special that needs to be done when the directive is using a controllerAs syntax? For example, instead of `person='{name: ...` I have `person='{vm.customer.name: "", vm.customer.address: "", ...'}` which doesn't seem to work as expected. – Raphael Rafatpanah Jan 20 '15 at 15:51
  • Are you using Angular 1.3.x? If so, you can use [bindToController](https://docs.angularjs.org/api/ng/service/$compile#-bindtocontroller-) option, which is one of the directive options. Please see my edited answer. – lvarayut Jan 20 '15 at 16:00
  • Thank you for your help. I got it working. Note that we should be logging $scope.vm.person, and not $scope.person for this to work. – Raphael Rafatpanah Jan 20 '15 at 16:20
  • Great that help :) Good notice, I changed it. – lvarayut Jan 20 '15 at 16:30
0

You can also have a callback function, telling reusable directive to invoke once it is done with processing.

here updateUser(user) function of parent controller would be invoked when we click save button on directive's template.

index.htl

<script src="app.js"></script>
<script src="userDirective.js"></script>
....
    <body ng-controller="MainCtrl">
      <p>Hello {{name}}!</p>
      <user-form update-user="updateUser(user)"></user-form>

app.js

angular.module('plunker', []).controller('MainCtrl', function($scope) {
  $scope.name = 'World';
  $scope.users = [{name: "Tars", gender: "male", email: "Tars@gmail.com"}];

  $scope.updateUser = function(user){
    $scope.users.push(user);
  }
});

user-directive.html

<div>
  <form novalidate class="css-form">
    Name: <input type="text" ng-model="user.name" required /><br />
    E-mail: <input type="email" ng-model="user.email" required /><br />
    Gender: <input type="radio" ng-model="user.gender" value="male" />male
    <input type="radio" ng-model="user.gender" value="female" />female<br />
    <input type="button" ng-click="reset()" value="Reset" />
    <input type="submit" ng-click="update(user)" value="Save" />
  </form>
</div>

userDirective.js

(function() {

  'use strict';

  function UserController($scope) {
    $scope.master = {};

    $scope.reset = function() {
      $scope.user = angular.copy($scope.master);
    };

    $scope.update = function(user) {
      $scope.updateUser({
        user: angular.copy(user)
      });
    }

    $scope.reset();
  }

  angular
    .module('plunker')
    .directive('userForm', User);

  function User() {
    return {
      scope: {
        updateUser: '&'
      },
      restrict: 'E',
      templateUrl: 'user-directive.html',
      replace: true,
      controller: UserController
    };
  }
})();

To know more about Parent Controller and Reusable isolated scoped directive communication options refer https://stackoverflow.com/a/27997711/288952

Community
  • 1
  • 1
Yogesh Manware
  • 1,843
  • 1
  • 22
  • 25