Milen Igrachev
Milen Igrachev

Reputation: 259

Angular: Implementing ng-click in directive with DOM manipulation?

I am Angular newbie and I am struggling with what I think to be a standard problem.

What I am trying to implement is a custom directive called "clicker" that is meant to be included in "ul ng-repeat" html elements.

Here is an example of how I imagine my HTML to be:

<ul ng-repeat="item in items">
    <clicker>{{item}}</clicker>
    ...
</ul>

To accomplish that I created a custom directive "clicker" here is how it looks like:

myModule.directive('clicker', function() {
return {
    restrict : 'E',
    replace : true,
    transclude: true,
    scope : true,
    template : '<li><a ng-click="showMeClicked()" ng-transclude></a></li>',

    controller: function($scope, $element, $document){
            var test = {}; //In debug $scope, $element, $document are injected here!

           $scope.showMeClicked = function ($scope, $element, $document) {
               //In debug all $scope, $element, $document are undefined here!

               //This line works and deletes all class properties of my <li> along with id properties of their
               //child <a> element. Since $element is undefined this code was the only way I manage to do that action.
               angular.element(document.querySelectorAll('.button_selected')).removeClass('button_selected').children().removeAttr('id');

               //This code does not work since $element is undefined!
               $element.addClass('button_selected');
               $element.children().prop('id', 'button_selected_font');

               //My expected result is:
               //'<li class="button_selected">'
               //     '<a id="button_selected_font" ng-click="showMeClicked()" ng-transclude></a>'
               //'</li>'
           };
         }
};
});

What I want to do is make my "clicker" elements clickable and on clicking them I want to change their appearance on the screen. Basically what I need is the $element to be properly injected to my showMeClicked function so I can use it to set my list's "class" and my anchor's "id". I tried to give good comments in my example code.

I tried to use link function instead of controller one, but the current element is not injected there too. The scope : true property that I have given to my directive is just for the example it may be changed if needed.

I am trying to avoid using jQuery and use the Angular's jqLite.

Do anyone have any suggestion?

Thanks in advance!

EDIT: At the moment I am not using the ng-repeat directive on my "ul". Instead I manually declared 9 "clicker" tags. As a result in my resulting HTML the tags are replaced with the proper code from the directive and I see a list of "li"s. You can see my "ul" content here: pastebin.com/JPFqcnSU

As I click on any of the links it results in the expected exception:

Cannot access addClass for undefined.

Upvotes: 2

Views: 2579

Answers (1)

Dieterg
Dieterg

Reputation: 16368

You need to access your current element by passing an index:

$element[0].style...

Javascript

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

function MyController(){
    var vm = this;

    this.items = ["a","b","c","d","e"];
}

app.controller('MyController',[MyController])
.directive('clicker',function() {
    return {
        restrict : 'E',
        replace : true,
        transclude: true,
        scope : true,   
        template : '<li><a href="#" ng-click="showMeClicked()" ng-transclude></a></li>',
        link: function(scope,element,doc) {
            scope.showMeClicked = function() {
                 element[0].style.backgroundColor = 'red';
                 angular.element(element[0]).find('a').addClass('magic');
            }
        }
    }
});

HTML

<div ng-app="myApp" ng-controller="MyController as vm">
    <div ng-repeat="item in vm.items">
        <clicker>{{item}}</clicker>
    </div>
</div>

Fiddle

Upvotes: 2

Related Questions