Question

how to call controller function from directive? or howto access directive ng-model from controller? eg. I use angular ui bootstrap time component and when time change I need to notify calling function in controller. I think in general it's typical use case for two way communication between components.

appControllers.controller('mainCtrl', ['$scope', 
  function($scope) {

    $scope.changedTime = function(time) {
        alert(time);        
    }

 }]).directive('timePicker',['$http', function($http) {
  return {
    restrict: 'AE',    
    templateUrl: 'partials/time-picker.html',
    scope: true,
    controller: 'TimepickerDemoCtrl'        
  };
}]);


//partials/time-picker.html:
<span ng-controller="TimepickerDemoCtrl">              
   <timepicker ng-model="mytime" ng-change="changed()" hour-step="hstep" minute-step="mstep" show-meridian="ismeridian"></timepicker>              
</span>


//TimepickerDemoCtrl (copy from source):
var TimepickerDemoCtrl = function ($scope) {
  $scope.mytime = new Date();
  $scope.hstep = 1;
  $scope.mstep = 15;

  $scope.options = {
    hstep: [1, 2, 3],
    mstep: [1, 5, 10, 15, 25, 30]
  };

  $scope.ismeridian = true;
  $scope.toggleMode = function() {
    $scope.ismeridian = ! $scope.ismeridian;
  };

  $scope.update = function() {       
    var d = new Date();
    d.setHours( 14 );
    d.setMinutes( 0 );
    $scope.mytime = d;
  };

  $scope.changed = function () {
    console.log('Time changed to: ' + $scope.mytime);
  };

};
Was it helpful?

Solution

Here is a skeleton app that demonstrates how you can call parent controller functions from directives while using isolate scope to avoid tight coupling (which enhances reusability):

JS:

angular.module('myApp', [])
.controller('MyController', function($scope){
  $scope.showAlert = function(value){
    alert('Called from directive: ' + value);
  };
})
.directive('myDirective', function(){
  return {
    restrict: 'E',
    scope: {
      alert: '&'
    },
    controller: function($scope){
      $scope.value = 'directive scope value';
    },
    template: '<button ng-click="alert({message: value})">Alert</button>'
  }
});

HTML:

<body ng-app="myApp" ng-controller="MyController">
  <my-directive alert="showAlert(message)"></my-directive>
</body>

Plunker using this code

The thing to focus on is the use of the & symbol in the scope: { ... } setting of the directive. In this case, it provide you with the ability to name the controller function in the alert attribute of your directive declaration in the HTML.

That function can then be called from the template of the directive.

Using isolate scope is a common pain point when learning about directives in Angular, but it is well-worth taking the time to wrap your head around.

Regarding the use of & in particular, I found this video to be especially helpful.

OTHER TIPS

My recommendation is to use $emit instead of calling a method of the controller directly in your directive.

Directives should be always independent components, if inside the directive there is a call to a method from a controller(outside the directive) this will create a dependency between my directive and the controller and of course this will force one not being able to exist without the other.

If I would have to apply a design principle to a directive it will be the S in SOLID, Single responsibility principle. Directives should be able to encapsulate and work independently.

On my controller the event is captured using $on like:

$scope.$on("ValueChanged", function(event, ars){
   ... //your event has been triggered.    
});

yes emit/on works also add that when there aren't parent/child hierarchy betwen controllers then it's need to inject $rootScope into subscriber controller.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top