181

I need to create a comma-separated list of items:

  <li ng-repeat="friend in friends">
      <b ng-repeat="email in friend.email">{{email}}{{$last ? '' : ', '}}</b>...
  </li>

According to the AngularJS documentation, no control flow statements is allowed in expressions. This is why my {{$last ? '' : ', '}} does not work.

Is there an alternative way to create comma-separated lists?

EDIT 1
is there something simpler than:

<span ng-show="!$last">, </span>
1
  • 5
    You can always use CSS to format lists in this way (then you don't need to modify HTML when your boss wants them on separate lines etc) - see stackoverflow.com/questions/1517220/… Commented Sep 2, 2015 at 15:25

9 Answers 9

342

You could do it this way:

<b ng-repeat="email in friend.email">{{email}}{{$last ? '' : ', '}}</b>

..But I like Philipp's answer :-)

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

6 Comments

Shouldn't ($last && '' || ', ') always yield ', '?
LIke okm above, I couldn't get angular to properly evaluate $last to true or false within a template. I used this: {{{true: '', false: ', '}[$last]}}. This technique is more flexible than using .join because it allows the elements in the list to each be members of an array, like: <b ng-repeat="friend in friends">{{friend.email}}{{{true: '', false: ', '}[$last]}}</b>
Updated to use ternary operators
How can i insert and in the printed array so that my array looks like this : John, Mike and Nil. How to get this format without using directive.
I'm using this approach since it allows me to use a filter on each value in the list.
|
233

Just use Javascript's built-in join(separator) function for arrays:

<li ng-repeat="friend in friends">
  <b>{{friend.email.join(', ')}}</b>...
</li>

4 Comments

If you want HTML-ish separators it's probably time to a write directive. You could also put HTML into join() and disable HTML escaping, but there's a special place in hell for that ;)
Nice, I didn't even think about using it this way.
@DavidKEgghead I beg to differ, jsfiddle.net/wuZRA. How does it not work for you?
@PhilippReichart sorry for the delay. Here is an example: jsfiddle.net/Sek8F -- looks like you are targeting a string where as I am referring to an object.
101

Also:

angular.module('App.filters', [])
    .filter('joinBy', function () {
        return function (input,delimiter) {
            return (input || []).join(delimiter || ',');
        };
    });

And in template:

{{ itemsArray | joinBy:',' }}

4 Comments

This answer shows "angular way" and should be marked as the best.
Why not save six lines and just do {{ itemsArray.join(', ') }}?
I'm not sure re-writing JavaScript core functions in AngularJS is really "the Angular way"...
This answer shows how Angular can add value for arrays of objects
42

.list-comma::before {
  content: ',';
}
.list-comma:first-child::before {
  content: '';
}
<span class="list-comma" ng-repeat="destination in destinations">
                            {{destination.name}}
                        </span>

2 Comments

This seems to the most "semantic" way, as the choice of using a comma-separated list is entirely about presentation. It could just as well have been a sublist.
This was the first solution that came to my mind. Less reliant on JavaScript.
10

You can use CSS to fix it too

<div class="some-container">
[ <span ng-repeat="something in somethings">{{something}}<span class="list-comma">, </span></span> ]
</div>

.some-container span:last-child .list-comma{
    display: none;
}

But Andy Joslin's answer is best

Edit: I changed my mind I had to do this recently and I ended up going with a join filter.

1 Comment

I'd go for a custom filter too, but I like your idea :)
5

I think it's better to use ng-if. ng-show creates an element in the dom and sets it's display:none. The more dom elements you have the more resource hungry your app becomes, and on devices with lower resources the less dom elements the better.

TBH <span ng-if="!$last">, </span> seems like a great way to do it. It's simple.

1 Comment

I like this approach, as it's simple and still supports html based separators. Thanks @the7erm!
3

Since this question is quite old and AngularJS had had time to evolve since then, this can now be easily achieved using:

<li ng-repeat="record in records" ng-bind="record + ($last ? '' : ', ')"></li>.

Note that I'm using ngBind instead of interpolation {{ }} as it's much more performant: ngBind will only run when the passed value does actually change. The brackets {{ }}, on the other hand, will be dirty checked and refreshed in every $digest, even if it's not necessary. Source: here, here and here.

angular
  .module('myApp', [])
  .controller('MyCtrl', ['$scope',
    function($scope) {
      $scope.records = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    }
  ]);
li {
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
  <ul>
    <li ng-repeat="record in records" ng-bind="record + ($last ? '' : ', ')"></li>
  </ul>
</div>

On a final note, all of the solutions here work and are valid to this day. I'm really found to those which involve CSS as this is more of a presentation issue.

Comments

1

I like simbu's approach, but I ain't comfortable to use first-child or last-child. Instead I only modify the content of a repeating list-comma class.

.list-comma + .list-comma::before {
    content: ', ';
}
<span class="list-comma" ng-repeat="destination in destinations">
    {{destination.name}}
</span>

Comments

0

If you are using ng-show to limit the values, the {{$last ? '' : ', '}} won`t work since it will still take into consideration all the values.Example

<div ng-repeat="x in records" ng-show="x.email == 1">{{x}}{{$last ? '' : ', '}}</div>

var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope) {
  $scope.records = [
    {"email": "1"},
    {"email": "1"},
    {"email": "2"},
    {"email": "3"}
  ]
});

Results in adding a comma after the "last" value,since with ng-show it still takes into consideration all 4 values

{"email":"1"},
{"email":"1"},

One solution is to add a filter directly into ng-repeat

<div ng-repeat="x in records | filter: { email : '1' } ">{{x}}{{$last ? '' : ', '}}</div>

Results

{"email":"1"},
{"email":"1"}

1 Comment

Any suggestion on how to solve this issue the same way in Angular 2 without creating a custom pipe?

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.