AngularJS ng-repeat, comma separated with 'and' before the last item

北战南征 提交于 2019-12-02 16:12:35

$last is the truthy value.. so it holds either true or false and it doesn't hold the last element index..

I guess below expression should solve your problem

<p><span ng-repeat="user in Users">
            {{user.Username}} {{$last ? '' : ($index==Users.length-2) ? ' and ' : ', '}}
  </span></p>

Also make sure that you have the expression with $last within ng-repeat element and not outside of it

Please check the below working fiddle

http://jsfiddle.net/hrishi1183/Sek8F/2/

This could be one of the solutions

<span data-ng-repeat="user in Users">{{user.Username}}<font ng-show="!$last">,</font></span>
<span ng-repeat="user in Users">{{$first ? '' : $last ? ' and ' : ', '}}{{user.Username}}</span>

Instead of appending something prepend it. You can use $first to omit the first one. You can then use $last to add "and" instead of a comma.

Use a comma before and to promote clarity!

Bill Gates donates 6 million to Username1, Username2 and Username3.

vs

Bill Gates donates 6 million to Username1, Username2, and Username3.

Without the serial comma, the sentence does not clearly indicate that each of the users is to be given an equal share.

<span ng-repeat="user in Users">
     {{user.Username}}{{$last ? '' : ($index==Username.length-2) ? ', and ' : ',&nbsp;'}}
</span>

Outputs:

Username1, Username2, Username3, and Username4

If you just need the text output, use a custom filter instead of ng-repeat:

<span>{{Users | humanizedUserList}}</span>

the filter code being something like this (using Lodash):

app.filter('humanizedUserList', function() {
  return function(users) {
    var last_users = _.last(users, 2);
    return _.reduce(users, function(out, user, idx, users) {
      out += user.UserName;

      if(user === last_users[1]) { // last entry
        return out;
      }
      else if(user === last_users[0]) { // second to last entry
        return out + ', and ';
      }
      else {
        return out + ', ';
      }
    });
  };
}

You'd save yourself the hackish use of $last outside of the ng-repeat and ternary operators - and add reusability for other parts of your application.

I ran into this problem today, but with an extra challenge that the list items may need to be formatted within the sentence (for example, bold items or links). So just outputting a string from a filter wouldn't work. Initially I tried using ng-bind-html and outputting HTML from the filter, but that wasn't flexible enough.

I ended up making a directive that can be used within any ng-repeat to add the separator between list items. The tricky part is I only had access to $first, $last, and $index (not the original array or its length!).

My solution:

var app = angular.module('app', []);
app.directive('listSeparator', function() {
  return {
    replace: true,
    template: '<span>{{ separator }}</span>',
    link: function(scope, elem, attrs) {
      scope.$watchGroup(["$index", "$first", "$last"], function() {
        if (scope.$first)
          scope.separator = "";
        else if (scope.$last && scope.$index == 1)
          scope.separator = " and ";
        else if (scope.$last)
          scope.separator = ", and ";
        else
          scope.separator = ",";
      })
    }
  }
})
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.10/angular.min.js"></script>
<div ng-app="app">
    Click a button to see the formatted list.
    <button ng-click="myArray = ['one']">One item</button>
    <button ng-click="myArray = ['one','two']">Two items</button>
    <button ng-click="myArray = ['one','two','three']">Three items</button><br>
    <span ng-repeat="item in myArray"><list-separator></list-separator>
        <strong>{{item}}</strong></span>

</div>

Enjoy!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!