Search code examples
javascriptjqueryangularjsjqlite

AngularJs Directive: How to dynamically set attributes on ng-repeat element


I am relatively new to AngularJS. While venturing into directive creation, I can across this problem: How to dynamically add / remove attributes on the children of the directive's element when these children are dynamically added with 'ng-repeat'?

First, I thought of this solution:

template

...
a.list-group-item(ng-repeat='playlist in playlists', ng-click='addToPlaylist(playlist, track)', ng-href='playlist/{{ playlist._id }})
...

*directive

link: function(scope, elm, attrs) {   
  var listItems = angular.element(element[0].getElementsByClassName('list-group-item')
  angular.forEach(listItems, function(item, index) {
    'add' in attrs ? item.removeAttr('href') : item.removeAttr('ng-click');
    listItems[index] = item;
  }
... 

Result

It turns out, my code never enters this angular.forEach loop because listItems is empty. I suppose it's because the ng-repeat is waiting for the scope.playlists to populate with the data from a async call to a server via $resource.

temporary fix

in the directive definition, I added a boolean variable that checks for the presence of 'add' in the element's attributes: var adding = 'add' in attrs ? true : false;

And then in the template,

a.list-group-item(ng-if='adding', ng-repeat='playlist in playlists', ng-click='addToPlaylist(playlist, track)')
a.list-group-item(ng-if='!adding', ng-repeat='playlist in playlists', ng-href='playlist/{{playlist._id }}')

While it works fine, it is obviously not DRY at all. HELP!


Solution

  • Instead of removing attributes, change your click handler.

    Add $event to the list of arguments and conditionally use preventDefault().

    <a ng-click='addToPlaylist($event,playlist)' ng-href='playlist'>CLICK ME</a>
    

    In your controller:

    $scope.addToPlaylist = function(event,playlist) {
         if (!$scope.adding) return;
         //otherwise
         event.preventDefault();
         //do add operation
    };
    

    When not adding, the function returns and the href is fetched. Otherwise the default is prevented and the click handler does the add operation.

    From the Docs:

    $event

    Directives like ngClick and ngFocus expose a $event object within the scope of that expression. The object is an instance of a jQuery Event Object when jQuery is present or a similar jqLite object.

    -- AngularJS Developer Guide -- $event