1

Is it possible to call the method defined inside the directive controller from outside.

<div ng-controller="MyCtrl"> <map></map> <button ng-click="updateMap()">call updateMap()</button> </div> app.directive('map', function() { return { restrict: 'E', replace: true, template: '<div></div>', controller: function(){ $scope.updateMap = function(){ //ajax call here. } }, link: function($scope, element, attrs) { $scope.updateMap(); //do some dom transformation } } }); 

I want to call the method updateMap() function from my view.

3 Answers 3

1

If you expose the function on the controller, instead of the scope, you can expose the controller on the parent scope, such as:

 controller: function($scope, $element, $attrs){ // Verify this. The controller has to be added to the parent scope, if the directive itself is creating a scope $scope.$parent[$attrs["name"]]=this; this.updateMap = function(){ //ajax call here. } }, 

Now in the main controller you will be able to access the controller:

<button ng-click="myMap.updateMap()">call updateMap()</button>

This is similar to how ng-model exposes its controller. Think of the controller as an API to your directive.

Sign up to request clarification or add additional context in comments.

3 Comments

While this works, this approach should surely be discouraged. The View now defines properties on the scope - a sole purview of the controller, which could lead to unexpected results. It promotes breaking separation of concerns because now the controller can call into the View... so, my point is, perhaps a cautionary disclaimer is in order in your answer.
I am not sure, what you mean when you say "t promotes breaking separation of concerns because now the controller can call into the View". This is one controller calling into another controller, which is providing a mechanism\API to manipulate the directive working. I have seen this in multiple directives i have worked over time.
required is used between directives, but in this case one controller is the View's controller, and the second controller is inside a directive.
0

It would be a bad practice to access a function from the controller as you want. But still you can bind the updateMap function to $rootScope thus it can be used globally and still pass the current scope as a parameter to it.

Eg,

$rootScope.updateMap = function($scope) { // use the scope to do the manipulation } <div ng-controller="MyCtrl"> <map></map> <button ng-click="updateMap(this)">call updateMap()</button> </div> 

Here passing 'this' in updateMap function will refer to the scope in which the element is wrapped. In the above example, 'this' will refer to the MyCtrl's $scope

Comments

0

I would suggest two options. One simple option is to use events:

<div ng-controller="MyCtrl"> <map></map> <button ng-click="updateMap()">call updateMap()</button> </div> app.directive('map', function() { return { restrict: 'E', replace: true, template: '<div></div>', controller: function(){ $scope.updateMap = function(){ //ajax call here. } }, link: function($scope, element, attrs) { $scope.$on('my.update.map.event', $scope.updateMap); } } }); app.controller('MyCtrl', function ($scope) { $scope.updateMap = function () { $scope.$broadcast('my.update.map.event'); }; }); 

This isn't a bad solution. You're not polluting the root scope (@Krishna's answer) and your map directive isn't adding an arbitrary value to your controller's scope (@Chandermani's answer).

Another option, if you want to avoid events, is to to use the controllerAs syntax to expose your map directive's controller.

<div ng-controller="MyCtrl"> <map controller="mapController"></map> <button ng-click="mapController.updateMap()">call updateMap()</button> </div> app.directive('map', function() { return { restrict: 'E', replace: true, scope: { 'controller': '=?' }, template: '<div></div>', //controllerAs creates a property named 'controller' on this //directive's scope, which is then exposed by the //'scope' object above controllerAs: 'controller', controller: function(){ this.updateMap = function(){ //ajax call here. } }, link: function($scope, element, attrs, ctrl) { ctrl.updateMap(); } } }); 

This is similar to @Chandermani's answer, but the coupling between your controller and your directive is much more explicit. I can tell from the view that the map directive is exposing its controller and that it will be called mapController in MyCtrl's scope.

(I found this idea here).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.