4

Issue with ng-repeat, AngularJS looping

I'm having trouble creating this loop structure using ng-repeat in angular js(ionic 1 app). When I use ng-repeat, the date is repeatedly shown along with each event in every loop. But I want to show the date only once for corresponding events as shown in the picture.

image

georgeawg
  • 48,608
  • 13
  • 72
  • 95
Ronald Babu
  • 166
  • 1
  • 7

3 Answers3

6

You need a groupBy filter, which you (write manually, or) get from angular-filter module. Simply set a JSON with events and dates listed together. Here is a small demo that you can adjust to your example:

var app = angular.module('myApp', ['angular.filter']);
app.controller('myCtrl', function($scope) {
  $scope.events = [{
      "date": "Sept-1",
      "event": "Event 1"
    },
    {
      "date": "Sept-1",
      "event": "Event 2"
    },
    {
      "date": "Sept-2",
      "event": "Event 3"
    },
    {
      "date": "Sept-2",
      "event": "Event 4"
    },
    {
      "date": "Sept-3",
      "event": "Event 5"
    },
  ]
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-filter/0.5.17/angular-filter.min.js"></script>

<body>

  <div ng-app="myApp" ng-controller="myCtrl">

    <div ng-repeat="(key, value) in events | groupBy: 'date'">
      - {{key}}
      <div ng-repeat="val in value">
        * {{val.event}}
      </div>
      <br>
    </div>

  </div>

</body>
</html>
georgeawg
  • 48,608
  • 13
  • 72
  • 95
Aleksey Solovey
  • 4,153
  • 3
  • 15
  • 34
  • **Note:** This solution requires adding a third-party library to the app. Namely [angular-filter](https://github.com/a8m/angular-filter). – georgeawg Aug 20 '18 at 16:54
3

You could* use two ng-repeats, one for the dates, and another inner ng-repeat for each event listed under the date. For example:

<div ng-repeat="date in $ctrl.dates">
  {{date}}
  <div ng-repeat="event in $ctrl.events[date]">
    <div>event</div>
  </div>
</div>

I don't know what your data structure looks like, but you can easily adapt that.

*Updated because of the other answer using groupBy. That answer works great. I personally prefer not to use the groupBy filter and instead opt for two data models that work in tandem.

Devin Fields
  • 2,066
  • 1
  • 10
  • 18
1

An alternative is to create a function that returns a date only if it is different than the previous date:

$scope.dateIfNew = function(index) {
    var event = $scope.events[index];
    if (index == 0) return event.date;
    var prevEvent = $scope.events[index-1];
    if (event.date != prevEvent.date) return event.date;
    //else
    return "";
};

This uses only a single ng-repeat. It avoids the extra performance overhead of a nested ng-repeat and avoids the use of a third-party library.

The DEMO

var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
  $scope.dateIfNew = function(index) {
    var event = $scope.events[index];
    if (index == 0) return event.date;
    var prevEvent = $scope.events[index-1];
    if (event.date != prevEvent.date) return event.date;
    //else
    return "";
  };
  $scope.events = [{"date": "Sept-1","event": "Event 1"},
                   {"date": "Sept-1","event": "Event 2"},
                   {"date": "Sept-2","event": "Event 3"},
                   {"date": "Sept-2","event": "Event 4"},
                   {"date": "Sept-3","event": "Event 5"},
                  ]
});
<script src="//unpkg.com/angular/angular.js"></script>

<body ng-app="myApp" ng-controller="myCtrl">
  <table>
    <tr ng-repeat="item in events">
      <td>
        <b>{{dateIfNew($index)}}</b>
      </td>
      <td>{{item.event}}</td>
    </tr>
  </table>  
</body>
Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95