2

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.

2
  • What happens at the moment? Do you see the directive appearing inside the template? Commented Apr 17, 2014 at 9:54
  • @Augier At the moment I am not using the ng-repeat directive on my <ul>. Instead I mannualy 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 Commented Apr 17, 2014 at 10:04

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

1 Comment

Big thanks, that did the trick!. It seems I needed link function instead of controller one and i needed to access my current element by passing the index. Now the DOM manipulation is doing just fine. Thanks!!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.