angularjscontrollerdirectiveisolate-scope

Angular JS directives with isolate scopes and internal controllers


I haven't touched angular js in a while and back when I did write, we used a flavour with typescript which was pretty straightforward with me. Now I want to write vanilla angular js and I feel I am a bit confused.

Problem:
I have a directive with a few variables in its isolate scope and I basically want to bind to this directive that is spawned inside a for each <ul> to a click event. I tried with directly binding a function on ng-click and with link element e.t.c. bind on click, but it seems I am doing something wrong since with the first way nothing happens, with the second way the two-way bound variable is undefined.

Here it goes: https://plnkr.co/edit/OOBMs8pYONLjUE9lQXla?p=preview

activity-header.html

<div>
<h4>
Activity Name: {{activity.activity_name}}
</h4>

<h6>    
Activity Start Date: {{activity.activity_start_date}}
</h6>

<h6>        
Activity End Date: {{activity.activity_end_date}}
</h6>

<h6>
Participants: {{activity.participants}}
</h6>
</div>

activity-header.js

var app = angular.module('mainApp');

/*
app.controller('activityHeaderCtrl', ['$scope', function($scope) {
    $scope.activity='';
    $scope.msg='';
    $scope.check = function() {
            alert($scope.msg);
        };
}]);
*/

app.directive('activityHeader', function() {
    return {
        restrict: 'AE',
        templateUrl: 'activity-header.html',
        controller: ['$scope', Controller],
        scope: {
            activity:'=',
            msg:'='         
        },
        link: function($scope, $element, attrs) {
        $element.bind('click', function($scope) {
            alert($scope.msg);
        })}
    };        
    function Controller($scope) {
        $scope.check = function() {
            alert($scope.msg);
        };

    }
});

index.html

<html ng-app="mainApp">

    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
    <script src="script-main.js"></script>
    <script src="activity-header.js"></script>

<body>

    <div ng-controller="ctrl">

        <h1>
            Major Bla bla System    
        </h1>

        <ul>        
            <li ng-repeat="x in events">                
                <div activity-header activity="x" msg="greetingsfriend" ng-click="check()"></div>
            </li>
        </ul>    

        <h6>
            Beta v.0.2
        </h6>

    </div>

</body>

</html>

script-main.js

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

app.controller('ctrl', function ($scope) {

    //$scope.events = ["Elections", "Protest", "Martial Law", "X-mas Celebration"];
    $scope.events = [
        {"activity_name": "Elections", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "1453"},
        {"activity_name": "Martial Law", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "1821"},
        {"activity_name": "Protest", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "1940"},
        {"activity_name": "X-mas Celebration", "activity_start_date": "31/12/2014", "activity_end_date": "31/12/2015", "participants": "2009"}
    ];

    $scope.salute = function () {
        alert('hello there');
    };

});

(By the way, I'm using Mozilla Firefox, otherwise I'd have to host it e.g. on node.js for the same origin policy, don't know how to turn it off in chrome/ internet explorer).


Solution

  • Any idea on how to handle the click?

    Your problem is that you are using $scope as the name for the first argument in the click handler function. That name is overriding the $scope argument from the linking function.

        //BAD
        link: function($scope, $element, attrs) {
        $element.bind('click', function($scope) {
            alert($scope.msg);
        })}
    

    Fix your code like this:

        //GOOD
        link: function(scope, element, attrs) {
            element.on('click', function clickHandler(event) {
                console.log(scope.msg);
            });
        }
    

    AngularJS jqLite invokes the click handler with a JQuery Event Object as the first argument not $scope.


    Is this the correct way to handle events on directives?
    Why doesn't the ng-click event ever work to call the function I have in my directive's controller?

    The ng-click directive binds to functions in the parent scope.

    To bind click events to functions on the directive's scope, use element.on(). It's how ng-click gets the event from the browser. Look at the source code.