3

I've the AngularJS code below, where I'm trying to provide a callback function called callback. I want to execute this method in my AngularJS code, but all possible ways I can think of fails, i.e something along the lines of

scope.callback();
scope.$apply(scope.callback());

What can I do in order to execute the provided callback (in this case someFunction)?

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script type="text/javascript">
    // module
    var starApp = angular.module('starApp', []);

    // directive
    starApp.directive('rating', function() {
        // directive definition object
        return { 
            // used as an attribute or element
            restrict: 'AE', 
            // ng-class: for each key-value pair of the object with a truthy value the corresponding key is used as a class name
            // ng-click: custom behavior when an element is clicked
            // ng-repeat: update templates when collection items are inserted/removed
            template: '<ul class="rating">' +
                      '<li ng-repeat="star in starArray" ng-class="star" ng-click="toggle($index)">' +
                      '\u2605' +
                      '</li>' +
                      '</ul>',
            // variables in scope of directive (passed in from HTML)
            scope: { 
                stars: '=stars', // '=' values of corresponding attributes
                max: '=max',
                callback: '&'
            },
            // executed after the template has been cloned and holds directive logic
            link: function(scope, elem, attrs) {

                var updateStars = function() {
                    scope.starArray = [];
                    for (var i = 0; i < scope.max; i++) {
                        scope.starArray.push({
                            filled: i < scope.stars
                        });
                    }
                };

                scope.toggle = function(index) {
                    scope.stars = index + 1;
                };

                scope.$watch('stars', function(oldValue, newValue) {
                    if (newValue) {
                        updateStars();
                    }
                });
            }
        }
    });

    var someFunction = function() {
        alert("test");
    };
</script>
<link rel="stylesheet" href="rating.css"/>
</head>
<body ng-app="starApp">
    <rating stars="3" max="5" callback='someFunction'/>
</body>
</html>
Alvaro Silvino
  • 9,441
  • 12
  • 52
  • 80
Shuzheng
  • 11,288
  • 20
  • 88
  • 186

2 Answers2

0

I understand what you want to accomplish but it doesn't work like this - your callback function should be parent scope of the directive - i.e. in angular controller, not just somewhere in global window scope.

& binding is for passing a method into your directive's scope so that it can be called within your directive. The method is pre-bound to the directive's parent scope, and supports arguments. For example if the method is hello(name) in parent scope, then in order to execute the method from inside your directive, you must call $scope.hello({name:'world'})

from : What is the difference between '@' and '=' in directive scope in AngularJS?

So if you call your scope attribute as 'callback' in template:

<body ng-app="starApp">
  <div ng-controler="test">
    <rating stars="3" max="5" callback='someFunction()'/>
  </div>

then you should have a controller

 starApp.controller("test", function( $scope ){
    $scope.callback = function(){
      //does smth
    };
});

and modify accordingly your directive to have that someFunction called

starApp.directive('rating', function() {
  //all other stuff
   link: function(scope, elem, attrs) {
    //here we call function of the controller
    scope.someFunction();

It works like this directive's link someFunction calls callback function in controller

UPD If you want to call some arbitrary function, you can have it by adding its call into your controllers function:

//you want to call this code, defined outside angular
window.test = function(alert('test'));

//in controller you do
$scope.callback = function(){
//does smth

//and also call our defined function
window.test();
};
Community
  • 1
  • 1
shershen
  • 9,875
  • 11
  • 39
  • 60
  • So I cannot just let the user define a function in plain Javascript and pass it in? This would be much easier, and doesn't require knowledge of AngularJS... – Shuzheng Nov 24 '15 at 14:09
  • No, unfortunately. Using AngularJS requires knowledge of AngularJS – shershen Nov 24 '15 at 14:11
0

You need to add the controller and add the function to the $scope

changed the alert to console.log to demonstrate

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<script type="text/javascript">
    // module
    var starApp = angular.module('starApp', []);
     starApp.controller("testCtrl", function($scope) {
       //create the controller and add the function to the $scope
      $scope.someFunction = function() {
          console.log("test");
        } 
      });
 
    // directive
    starApp.directive('rating', function() {
        // directive definition object
        return { 
            // used as an attribute or element
            restrict: 'AE', 
            // ng-class: for each key-value pair of the object with a truthy value the corresponding key is used as a class name
            // ng-click: custom behavior when an element is clicked
            // ng-repeat: update templates when collection items are inserted/removed
            template: '<ul class="rating">' +
                      '<li ng-repeat="star in starArray" ng-class="star" ng-click="toggle($index)">' +
                      '\u2605' +
                      '</li>' +
                      '</ul>',
            // variables in scope of directive (passed in from HTML)
            scope: { 
                stars: '=stars', // '=' values of corresponding attributes
                max: '=max',
                callback: '&'
            },
            // executed after the template has been cloned and holds directive logic
            link: function(scope, elem, attrs) {
                
                var updateStars = function() {
                    scope.starArray = [];
                    for (var i = 0; i < scope.max; i++) {
                        scope.starArray.push({
                            filled: i < scope.stars
                        });
                    }
                };
                
                scope.callback(); //then call the function
                scope.toggle = function(index) {
                    scope.stars = index + 1;
                };
                
                scope.$watch('stars', function(oldValue, newValue) {
                    if (newValue) {
                        updateStars();
                    } 
                });
            }
        }
    });

    
</script>
<link rel="stylesheet" href="rating.css"/>
</head>
<body ng-app="starApp" ng-controller="testCtrl">
     
    <rating stars="3" max="5" callback='someFunction()'/>
       
</body>
</html>
Alvaro Silvino
  • 9,441
  • 12
  • 52
  • 80
  • Awesome. So it is not possible just to provide a callback function like in in Javascript button click-event? Here, someone who is using my directive must know how to create a controller in order to provide a callback? – Shuzheng Nov 24 '15 at 14:29
  • You have to make your function 'visible' to the framework. Whoever will use your directive will need to define the function in their controller too. So, the best practice is to do like this, if you really need to define the function in plain text, you will need to search the function on global scope and then execute it: http://stackoverflow.com/questions/493833/list-of-global-user-defined-functions-in-javascript – Alvaro Silvino Nov 24 '15 at 14:38