Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angularjs directive call function specified in attribute and pass an argument to it

I want to create a directive that links to an attribute. The attribute specifies the function that should be called on the scope. But I also want to pass an argument to the function that is determined inside the link function.

<div my-method='theMethodToBeCalled'></div> 

In the link function I bind to a jQuery event, which passes an argument I need to pass to the function:

app.directive("myMethod",function($parse) {   restrict:'A',   link:function(scope,element,attrs) {      var expressionHandler = $parse(attrs.myMethod);      $(element).on('theEvent',function( e, rowid ) {         id = // some function called to determine id based on rowid         scope.$apply(function() {expressionHandler(id);});      }   } }  app.controller("myController",function($scope) {    $scope.theMethodToBeCalled = function(id) { alert(id); }; } 

Without passing the id I can get it working, but as soon as I try to pass an argument, the function is not called anymore

like image 317
rekna Avatar asked Jul 09 '13 19:07

rekna


2 Answers

Marko's solution works well.

To contrast with recommended Angular way (as shown by treeface's plunkr) is to use a callback expression which does not require defining the expressionHandler. In marko's example change:

In template

<div my-method="theMethodToBeCalled(myParam)"></div> 

In directive link function

$(element).click(function( e, rowid ) {   scope.method({myParam: id}); }); 

This does have one disadvantage compared to marko's solution - on first load theMethodToBeCalled function will be invoked with myParam === undefined.

A working exampe can be found at @treeface Plunker

like image 124
johans Avatar answered Sep 24 '22 16:09

johans


Just to add some info to the other answers - using & is a good way if you need an isolated scope.

The main downside of marko's solution is that it forces you to create an isolated scope on an element, but you can only have one of those on an element (otherwise you'll run into an angular error: Multiple directives [directive1, directive2] asking for isolated scope)

This means you :

  • can't use it on an element hat has an isolated scope itself
  • can't use two directives with this solution on the same element

Since the original question uses a directive with restrict:'A' both situations might arise quite often in bigger applications, and using an isolated scope here is not a good practice and also unnecessary. In fact rekna had a good intuition in this case, and almost had it working, the only thing he was doing wrong was calling the $parsed function wrong (see what it returns here: https://docs.angularjs.org/api/ng/service/$parse ).

TL;DR; Fixed question code

<div my-method='theMethodToBeCalled(id)'></div> 

and the code

app.directive("myMethod",function($parse) {   restrict:'A',   link:function(scope,element,attrs) {      // here you can parse any attribute (so this could as well be,      // myDirectiveCallback or multiple ones if you need them )      var expressionHandler = $parse(attrs.myMethod);      $(element).on('theEvent',function( e, rowid ) {         calculatedId = // some function called to determine id based on rowid          // HERE: call the parsed function correctly (with scope AND params object)         expressionHandler(scope, {id:calculatedId});      }   } }  app.controller("myController",function($scope) {    $scope.theMethodToBeCalled = function(id) { alert(id); }; } 
like image 39
Robert Bak Avatar answered Sep 21 '22 16:09

Robert Bak