2

I want to call a function defined in a directive, just the opposite of this stackoverflow question

I tried this but does not work.

app.directive('myDirective', function() {
    return {
        link: function(scope, element, attrs) {
            scope.someDirectiveFn = function(arg) {
                 return "in directive";
            };
        },
    }
});

function MyCtrl($scope) {
    alert($scope.someDirectiveFn());
}

Is that possible? how could I get it? is it a bad practice?

EDIT

I got this way:

.controller('MyCtrl', function($scope) {
    alert($scope.func());
})

.directive('myDirective', function() {
    return {
      controller: function($scope, $element){
        $scope.func = function() {
          return "text";
         };
      }
    }
});

3 Answers 3

3

You can use event system to achieve that.

First, emit a custom event on your scope with your parameters. Second, listen to the scope in your directive with angular $on method.

app.controller('MyCtrl', function($scope) {
  $scope.invokeDirectiveMethod = function() {
    $scope.$emit('invokeMyDirectiveMethod', 'myParameter');
  };
})

.directive('myDirective', function() {
  return {
    link: function(scope, element, attrs) {
      var someDirectiveFn = function(event, arg) {
        alert(arg + " in directive");
      };

      scope.$on('invokeMyDirectiveMethod', someDirectiveFn);
    },
  }
});

Here is a working plunker.

UPDATE

Based on your update, event communication does not fit your problem.

How about passing an object to directive using two way binding and defining someDirectiveFn in that object? This way you can pass arguments and return values from it.

app.controller('MyCtrl', function($scope) {
  $scope.shareObject = {};

  $scope.invokeDirectiveMethod = function() {
    if (angular.isFunction($scope.shareObject.someDirectiveFn)) {
      $scope.message = $scope.shareObject.someDirectiveFn('from controller'); 
    }
  };
})

.directive('myDirective', function() {
  return {
    scope: {
      'shareObject': '='
    },
    link: function(scope, element, attrs) {
      scope.shareObject.someDirectiveFn = function(arg) {
        return arg + ' from parameter';
      };
    },
  }
});

Updated plunker.

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

4 Comments

$emit is nice, but it can not help me when I need to return a value from directive. I edited my question to explain better.
It works, thank you very much. I got another approach(check question), could you tell me what you think about it? what's better? best practice?
well, this is not the best way to communicate actually. But i don't know if you really have to call a directive method? What is your actual use case for this scenario? I might suggest a better way to if you provide it.
Right, that's exactly what I meant. You have to ask yourself one simple question: Do I want to modify the directive with that function in any way? - If not, your design is wrong. Your method shouldnt be in the directive then.
1

You didnt post your html code, so I assume that your custom directive is used IN MyCtrl. This does not work because of when the functions are executed.

Controller functions are always executed before link functions.

Here is a cool article about the differences.

So if you want your controller to be able to invoke a function in the directive you can broadcast events (like in halilb's answer) or make the directive to listen to specific scope values, like this:

app.directive('myDirective', function() {
    return {
        link: function(scope, element, attrs) {
            scope.$watch("message", function() { console.log(message); });
        },
    }
});

function MyCtrl($scope) {
    $scope.message = "Hello Directive";
}

4 Comments

Good article but I need directive to return some value. I edited my question to explain better.
@Andres - Well, why you want to add that function to the directive then? You would only place it in the link function of the directive if you want to manipulate the directives DOM from your controller. Otherwise, just define the function in the controller.
Do you mean to define it in the directive's controller? something like plnkr.co/edit/GzJ8LIbhLh17XW9e2XYT?p=preview ??
@Andres - No, I mean. For what reason do you use the directive at all? If the return value does not affect the directive, then it is useless to define the method IN the directive. Just do the calculation in your MyCtrl
0

I'm guessing you want to have a function that is shared between a directive and a controller lets say?

if thats the case how about creating a service and injecting the service into both directive and ctrl. This way you would only have to create it once.

  app.service('sharedFucntionService', function() {
     return {
        someFn : function (arg) {
             alert(arg + " in directive")  
        }
    }
 });

Injecting the service into a directive

 app.directive('myDirective',function( sharedFucntionService){
  return {
        link: function (scope, element, attrs) {
            // do something with sharedFucntionService
        }
    }

});

Inject the service into the controller as well function MyCtrl($scope, sharedFucntionService){ ...... }

1 Comment

I prefer avoid service/factory for this task, I guess there should be an easier approach

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.