1

I'm having some trouble relating to the use of ng-repeat with multiple elements. Consider the following html:

<li>
    <a href="/">Link</a>
</li>
<li class="divider-vertical"></li>

I want to repeat that for every link but I can't because the ng-repeat would go on the li, and therefore miss the divider li.

Another (somewhat inconclusive) stackoverflow thread had the following directive:

app.directive('dividerVertical', function() {
  return {
    restrict: 'A',
      link: function(scope, element, attrs) {
        element.after('<li class="divider-vertical"></li>');
      }
  }
});

Used like this:

<li ng-repeat="link in links" divider-vertical>
   <a href="{{ link.path }}">{{ link.name }}</a>
</li>

This gives me the following:

Link1 Link2 Link3 | | |

Rather than the desired:

Link1 | Link2 | Link3

I am not sure if there's something I'm doing wrong there or if the approach is fundamentally wrong.

This feels like it should be very simple to achieve and maybe I've gone off entirely on the wrong path, any pointers would be much appreciated.

madth3
  • 7,275
  • 12
  • 50
  • 74
matthewrk
  • 677
  • 10
  • 22
  • don't append dom stuff, please – Ven Jun 17 '13 at 11:10
  • I'm only doing it out of necessity, give me an alternative and I'll take it :) – matthewrk Jun 17 '13 at 11:16
  • 2
    @user1737909 What's wrong with appending to DOM? – Stewie Jun 17 '13 at 11:31
  • possible duplicate of [How would I render a dynamic definition list using angular?](http://stackoverflow.com/questions/10457833/how-would-i-render-a-dynamic-definition-list-using-angular) – Stewie Jun 17 '13 at 11:34
  • @Stewie - noted, I did check that thread before posting but its not a solution that's available in stable now? If I copy the angular.js file from the Plunker link I get "Error: 'undefined' is not a function (evaluating 'node.hasAttribute(attrStart)')" – matthewrk Jun 17 '13 at 12:06

2 Answers2

1

UPDATE: changed $timeout to scope.$evalAsync to ensure no flicker and align it to the angular way. see this answer

ng-repeat hasn't added the element to the dom yet. Wrapping your append in a timeout will do the trick.

Demo

app.directive('dividerVertical', ['$timeout', function($timeout) {
  return {
    restrict: 'A',
      link: function(scope, element, attrs) {
        //added this since I think this is the actual use case ;)
        if(!scope.$last) {
          scope.$evalAsync(function() {
            element.after('<li class="divider-vertical">|</li>');
          });
        }
      }
  }
}]);

PS: there is nothing special about the $timeout here, setTimeout will work just as well, but I like to keep things consistent with angular world.

Community
  • 1
  • 1
Liviu T.
  • 23,584
  • 10
  • 62
  • 58
1

I think the current way to handle this would be using ng-repeat-start and ng-repeat-end. You could also get rid of the divider after the last link by looking at the $last variable from the ngRepeat directive

<li ng-repeat-start="link in links">
  <a href="{{link.path}}">{{link.name}}</a>
</li>
<li ng-if="!$last" class="divider-vertical" ng-repeat-end></li>
bbak
  • 3,057
  • 2
  • 20
  • 17