Triggering a function with ngClick within ngTransclude

1.7k views Asked by At

I have an unordered list loaded with four items from an array while using ngRepeat. The anchor tag in the list item has a function in the ngClick attribute that fires up a message. The function call works well when used like this:

<ul>
  <li ng-repeat="n in supsNames">
    <a ng-click="myAlert(n.name)">{{n.name}}</a>
  </li>
</ul>

I created a simple directive for inserting unordered lists with list items. The list is loaded just fine but the same functioned I previously mentioned does not fire up. The code is as follows:

<div list items="supsNames">
  <a ng-click="myAlert({{item.name}})">{{item.name}}</a>
</div>

Here is my javascript and angularjs code:

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

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

$scope.title = 'ngClick within ngTransclude';
$scope.supsNames = [
    {"name" : "Superman"},
    {"name" : "Batman"},
    {"name" : "Aquaman"},
    {"name" : "Flash"}
  ];

  $scope.myAlert = function(name) {
    alert('Hello ' + name + '!');
  };
});

app.directive('list', function() {

return {

restrict: 'A',
scope: {
  items: '='
},
templateUrl: 'list.html',
transclude: true,
link: function(scope, element, attrs, controller) {
  console.log(scope);
}

};

});

I also have a plnkr in case you want to see what I tried to do: http://plnkr.co/edit/ycaAUMggKZEsWaYjeSO9?p=preview

Thanks for any help.

3

There are 3 answers

0
ccnokes On BEST ANSWER

I got the plunkr working. I'm not sure if its exactly what you're looking for. I copied the main code changes below.

Here's the plunkr:

http://plnkr.co/edit/GEiGBIMywkjWAaDMKFNq?p=preview

The modified directive looks like this now:

app.directive('list', function() {
  return {
    restrict: 'A',
    scope: {
      items: '=', 
      ctrlFn: '&' //this function is defined on controller
    },
    templateUrl: 'list.html',
    transclude: true,
    link: function(scope, element, attrs, controller) {

      //directive fn that calls controller defined function
      scope.dirFn = function(param) {
        if(scope.ctrlFn && typeof scope.ctrlFn == 'function') { //make sure its a defined function
          scope.ctrlFn( {'name': param} ); //not sure why param has to be passed this way
        }
      }

    }

  };

});

And here's how it's called in the html file that's bound to your controller:

<div list items="supsNames" ctrl-fn="myAlert(name)">
  <a ng-click="dirFn(item.name)">{{item.name}}</a>
</div>

I think what was happening before is that you were trying to use a function defined in your controller within the isolated scope of the directive, so it wasn't working--that function was undefined in the directive. So what I did was added another parameter to the directive that accepts method binding (I think that's what its called) with the '&'.

So basically you pass your controller method to the directive, and that method gets invoked however you want by the directive defined method I creatively named "dirFn". I don't know if this is the best way per se, but I've used it in an existing project with good results ;)

2
haki On

you need to pass the function to the directive

scope: {
   items: '=', 'myAlert': '='
},
0
pdorgambide On

The ng-repeat inside the template of the directive insert a new scope and it require to call transclude funcion manually to work. I suggest remove ng-repeat and make the transclusion manually passing a copy of the controller scope and setting the item on each copy:

for(var i=0,len=scope.items.length;i<len;i++){
    var item=scope.items[i];
    var itemScope=scope.$parent.$new();
    $transcludeFn(itemScope, function (clone,scope) {
                // be sure elements are inserted
                // into html before linking
                scope.item=item;
                element.after(clone);
    });
  };

I edit the pluker and I hope that could be helpfull: http://plnkr.co/edit/97ueb8SFj3Ljyvx1a8U1?p=preview

For more info about transclusion see: Transclusion: $transcludeFn