1

I am creating a directive in angularJS which will replace my custom element with some elements (pagination), the elements which are generated by the directive has ng-click attribute and the value of ng-click attribute is the function of controller but the ng-click is not working

The element is

<my-element totalCount="5"></my-element>

The controller is

.controller('AppControler',['$scope'],function($scope){
    $scope.function1 = function(value){
        console.log('in function1 value = '+value);
    }
});

The directive is

.directive('myElement',function(){
    return{
        restrict: 'E',
        replace: true,
        scope:{
            totalCount: '@'
        },
        template: '<ul class="pagination"></ul>`,
        controller: function($scope, $element, $attrs){
            $scope.draw = function(){
                $($element).empty();
                for (var i=1; i<=$scope.totalCount; i++){
                    var link = $('<li><a href="javascript:;" ng-click="function1('+i+');">'+i+'</a></li>');
                    $($element).append(link);
                }
            }
        },
        link: function(scope, element, attr, controller){
            attr.$observe('totalCount', function(){
                scope.draw();
            });
        }
    };
});

But when I click on the <li> element the function1 of AppController is not invoked.

UPDATE1

Actually my directive has the isolate-scope and if I compile the element with $($element).append($compile(link)($scope)); then the element linked with the directive's scope but I want to compile the element with parent's scope

UPDATE2

I have made some changes in my-element like

<my-element totalCount="5" func-to-call="function1()"></my-element>

In directive

.directive('myElement',function($compile){
    return{
        ...
        ...
        scope:{
            totalCount: '@',
            funcToCall: '&'
        },
        ...
        controller: function($scope, $element, $attrs){
            $scope.draw = function(){
                ....
                ....
                var link = $('<li><a href="javascript:;" ng-click="function2('+i+');">'+i+'</a></li>');
                $($element).append($compile(link)($scope));
                ....
                ....
            }
            $scope.function2 = function(value){
                console.log('function2 value = '+value);
                $scope.funcToCall(value);
            }
        }
        ....
        ....
    };
});

in this case function2 of directive scope is calling and printing the value in console but $scope.funcToCall(value) is giving the error as

TypeError: Cannot use 'in' operator to search for 'function1' in <3>

UPDATE3

Created PLUNKER

Dau
  • 8,578
  • 4
  • 23
  • 48
  • The parent scope is restricted in ``myElement`` directive as it has ``isolated scope`` set. To invoke function in controller from directive, need to pass controller function to directive and refer it as scope by using ``&`` inside directive. Refer https://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope. Hope this helps and if possible create a fiddle or plunker replicating this issue. – Sameer K Sep 10 '15 at 07:02
  • @SameerK Plunker link added please look when you click on any page number you will get the error – Dau Sep 10 '15 at 07:36
  • You missed pass value in directive call ````. Please see working PLUNKER at http://plnkr.co/edit/LFgiTyG5zcSdqfkGq1qZ?p=preview. I have modified the the params are passed to controller function. using reference method. – Sameer K Sep 10 '15 at 08:12
  • @SameerK have you checked the console log? please look, its not working, function2 is printing the value but function1 of parent scope is not called (error in console) – Dau Sep 10 '15 at 08:16
  • 1
    Not why plunker is not getting updated. Make below changes and it will work. ```` and ``$scope.funcToCall()(value);`` – Sameer K Sep 10 '15 at 08:21
  • Hey Great Thanks @SameerK I have updated the plunker, please add your solution in answer with detail, I will mark it as accepted. – Dau Sep 10 '15 at 08:25

3 Answers3

1

You have an isolated scope in your directive , to access the parent function you will need to pass that function and for that you can use "&" in your directive.

scope:{
    totalCount: '@',
    fnt : '&'
 }

bind it to ng-click ng-click="fnt()"

and to pass it from the parent the element will be like this :

<my-element totalCount="5" fnt="parentFunction"></my-element>
0

You need to use $compile before adding it in DOM like,

var link = '<li><a href="javascript:;" ng-click="function1('+i+');">'+i+'</a></li>';
$($element).append($compile(link)($scope));

This problem is similar to Dynamic content added with AngularJS click event not working on the added content

Update: You can pass = control for bi-directional binding like,

scope: {
  control: '='
},

Final Updated no need to add another call $scope.$parent.function1(value); in your function2 call like,

$scope.function2 = function(value){
    console.log('function2 value = '+value);
    $scope.$parent.function1(value);
}

Demo

Community
  • 1
  • 1
Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
  • function1 is defined in the AppController not inside the directive, If I define the function1 within directive then its working fine with $compile but its not calling the function1 of AppController – Dau Sep 10 '15 at 06:26
  • Because the directive has the isolate scope the elements linked to directive scope, but I want to link the element with parent scope – Dau Sep 10 '15 at 06:31
  • Plunker link added please look when you click on any page number you will get the error – Dau Sep 10 '15 at 07:37
0

To invoke external function (controller function) in your case from directive when directive has isolated scope set, need to pass the controller function to directive like below.

<my-element func-to-call="function1" total-count="5"></my-element>

Then this function will be available in directive as local isolated scope as

scope: { totalCount: '@', funcToCall: '&' },

Further we can have function inside directive controller to call this external function (of course there are other ways too) like

$scope.function2 = function(value){       
      $scope.funcToCall()(value);
    }

Then finally we can call $scope.function2 in directive's element like var link = $('<li><a ng-click="function2('+i+');">'+i+'</a></li>');

Below is the complete directive code.

app.directive('myElement', function($compile){
return{
  restrict: 'E',
  replace: true,
  scope: {
    totalCount: '@',
    funcToCall: '&' 
  },
  template: '<ul class="pagination"></ul>',
  controller: function($scope, $element, $attrs){

    $scope.draw = function(){
      $($element).empty();
      for (var i=1; i<$scope.totalCount; i++){
        var link = $('<li><a ng-click="function2('+i+');">'+i+'</a></li>');
        $($element).append($compile(link)($scope));
      }
    }

    $scope.function2 = function(value){
      //console.log('function2 value = '+value);
      $scope.funcToCall()(value);
    }
  },
  link: function(scope, element, attr, controller){
    scope.draw();
  }
};
});
Sameer K
  • 799
  • 1
  • 7
  • 26