170

I have a example angularJS

<div ng-controller="testCtrl">

<test color1="color1" updateFn="updateFn()"></test>
</div>
 <script>
  angular.module('dr', [])
.controller("testCtrl", function($scope) {
    $scope.color1 = "color";
    $scope.updateFn = function() {
        alert('123');
    }
})
.directive('test', function() {
    return {
        restrict: 'E',
        scope: {color1: '=',
                updateFn: '&'},
        template: "<button ng-click='updateFn()'>Click</button>",
        replace: true,
        link: function(scope, elm, attrs) { 
        }
    }
});

</script>
</body>

</html>

I want when I click button, the alert box will appear, but nothing show.

Can anyone help me?

0

7 Answers 7

253

To call a controller function in parent scope from inside an isolate scope directive, use dash-separated attribute names in the HTML like the OP said.

Also if you want to send a parameter to your function, call the function by passing an object:

<test color1="color1" update-fn="updateFn(msg)"></test>

JS

var app = angular.module('dr', []);

app.controller("testCtrl", function($scope) {
    $scope.color1 = "color";
    $scope.updateFn = function(msg) {        
        alert(msg);
    }
});

app.directive('test', function() {
    return {
        restrict: 'E',
        scope: {
            color1: '=',
            updateFn: '&'
        },
        // object is passed while making the call
        template: "<button ng-click='updateFn({msg : \"Hello World!\"})'>
            Click</button>",
        replace: true,        
        link: function(scope, elm, attrs) {             
        }
    }
});

Fiddle

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

9 Comments

Thank Codezilla for your answer, and I want to ask about the circumstance when I want to bind the function "updateFn" from parent scope to isolate scope in directive "test", is that possible?
The replace attribute has been deprecated in AngularJS: stackoverflow.com/questions/24194972/…
for some reason the argument is undefined for me.
@chovy I think the argument is only used once you call the method again? The first open bracket usage seems to be the format that angular wants for the method to just be passed, but I might be wrong there
An object mapping updateFn({msg: 'my message'}); has to be used in that format when making the function call inside the directive's link function.
|
168

Perhaps I am missing something, but although the other solutions do call the parent scope function there is no ability to pass arguments from directive code, this is because the update-fn is calling updateFn() with fixed parameters, in for example {msg: "Hello World"}. A slight change allows the directive to pass arguments, which I would think is far more useful.

<test color1="color1" update-fn="updateFn"></test>

Note the HTML is passing a function reference, i.e., without () brackets.

JS

var app = angular.module('dr', []);

app.controller("testCtrl", function($scope) {
    $scope.color1 = "color";
    $scope.updateFn = function(msg) {        
        alert(msg);
    }
});

app.directive('test', function() {
    return {
        restrict: 'E',
        scope: {
            color1: '=',
            updateFn: '&'
        },
        // object is passed while making the call
        template: "<button ng-click='callUpdate()'>
            Click</button>",
        replace: true,        
        link: function(scope, elm, attrs) {       
          scope.callUpdate = function() {
            scope.updateFn()("Directive Args");
          }
        }
    }
});

So in the above, the HTML is calling local scope callUpdate function, which then 'fetches' the updateFn from the parent scope and calls the returned function with parameters that the directive can generate.

http://jsfiddle.net/mygknek2/

10 Comments

Not sure how I can get a down vote for something that works ?? You should leave a comment if going to down vote.
This worked for me. If you don't want the extra function just write ng-click="updateFn()('Directive Args')"
Awwww ! scope.updateFn()("Directive Args"); !! NOT scope.updateFn("Directive Args"); !!!
This is more perfect answer indeed !!
@Ludwik11 sure - its because scope.updateFn when defined like this is a function that returns a function (hence the ()()) and this is because we pass into scope (via update-fn="updateFn" in html) a reference to the function we want called. The 1st () is a call to angular to return this reference, the 2nd () makes the call to our function and is where we pass any parameters. HTH
|
39

In your 'test' directive Html tag, the attribute name of the function should not be camelCased, but dash-based.

so - instead of :

<test color1="color1" updateFn="updateFn()"></test>

write:

<test color1="color1" update-fn="updateFn()"></test>

This is angular's way to tell the difference between directive attributes (such as update-fn function) and functions.

1 Comment

thanks for the catch. I have included that in my answer. Voted up! :)
10

How about passing the controller function with bidirectional binding? Then you can use it in the directive exactly the same way as in a regular template (I stripped irrelevant parts for simplicity):

<div ng-controller="testCtrl">

   <!-- pass the function with no arguments -->
   <test color1="color1" update-fn="updateFn"></test>
</div>

<script>
   angular.module('dr', [])
   .controller("testCtrl", function($scope) {
      $scope.updateFn = function(msg) {
         alert(msg);
      }
   })
   .directive('test', function() {
      return {
         scope: {
            updateFn: '=' // '=' bidirectional binding
         },
         template: "<button ng-click='updateFn(1337)'>Click</button>"
      }
   });
</script>

I landed at this question, because I tried the method above befire, but somehow it didn't work. Now it works perfectly.

Comments

6

use dash and lower case for attribute name ( like other answers said ) :

 <test color1="color1" update-fn="updateFn()"></test>

And use "=" instead of "&" in directive scope:

 scope: { updateFn: '='}

Then you can use updateFn like any other function:

 <button ng-click='updateFn()'>Click</button>

There you go!

4 Comments

Why would you use '=' instead of '&' ? when I tried this it kept on repeatedly calling my function.
It's wrong to use '=' for this. That is for two way object binding.
I think, the only problem is the use of parentheses in the first template. This executes the function then binds the result. Instead You should pass only the name of the function, like this: update-fn="updateFn"
Bad answer. very bad.
4

I had to use the "=" binding instead of "&" because that was not working. Strange behavior.

1 Comment

This is because you're most likely passing the directive a JS function reference instead of the execution. When you pass the function as an argument to the directive update-fn="updateFn()" you must include the parenthesis (and maybe params). Passing it as a function reference update-fn="updateFn" will not work with the & binding
0

@JorgeGRC Thanks for your answer. One thing though, the "maybe" part is very important. If you do have parameter(s), you must include it/them on your template as well and be sure to specify your locals e.g. updateFn({msg: "Directive Args"}.

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.