2

I have an angularJS controller with a list of Events. Every event has Date and Comment. I'm displaying a list of events and want to hide the same dates.

For instance if I have:

{Date: "10/1/2013", Comment= "First Event"},
{Date: "10/1/2013", Comment= "Second Event"},
{Date: "10/2/2013", Comment= "Third Event"}

The output should be:

 10/1/2013 Tuesday
     First Event

     Second Event

 10/2/2013 Wednesday
     Third Event

Here is my template:

<div data-ng-repeat="item in Events  | filter:Filter | orderBy:SortBy:SortDesc">

    <div data-ng-show="item.DisplayDate($index)" class="eventDate">{{ item.Date | date: 'M/dd/yyyy EEEE' }}</div>

    <div class="comment" ng-bind-html-unsafe="item.Comment"></div>
    <div style="clear:both"><br /></div>
</div>

I added a function to each Event item which compares event dates and if previous event has the same date returns false (hides Event Date div).

 $scope.DisplayDate = function (idx) {

             if (idx > 0) {
             //get previous event
                 var previousEvt = $scope.Events[idx - 1];
                 //if previous event has the same date as this one - don't show subheader
                 if (previousEvt.Date.getTime() ==  $scope.Events[idx].Date.getTime())
                     return false;
                 else
                     return true;
             }
             else
                 return true;


         }

It works great if we do not apply filter or order to the Events array. If order/filter is applied - DisplayDate method is evaluated on original Events array (which is incorrect).

The questions are:

  1. Is it possible to get access to filtered/ordered Events array in the DisplayDate method?
  2. Are there any other ways to show/hide group headers? I think I can apply some Date groupping and have two nested ng-repeats but it looks more complicated.

Thanks,

Sergei Rudakov
  • 558
  • 1
  • 4
  • 11
  • Probably this would help: http://stackoverflow.com/questions/14866185/number-of-items-in-a-list-filtered-angularjs. You could create a filtered/ordered list and key on that instead of accessing $scope.Events, which is why it processes the original list all the time. – rajasaur Oct 30 '13 at 12:10
  • I hound a great solution here: [link](http://stackoverflow.com/questions/11721863/angularjs-how-to-get-an-ngrepeat-filtered-result-reference) so I need to create custom filter, apply it to ng-repeat using '| [filterName] "[scope variable]"' syntax and then filtered array will be available in controller – Sergei Rudakov Oct 30 '13 at 12:30
  • did you find a good solution? – ricricucit Dec 09 '13 at 08:37

2 Answers2

1
  1. This is an educated guess but I'd say "with difficulty"

  2. The way I'd go around it (just did something similar with pagination + sorting):

In controller add:

$scope.EventsPreProccessed = [];

$scope.$watch('Events', function() {
  // here goes code that generates EventsPreProccessed into a form convenient for use in ng-repeat 
});

Every time your initial set of events changes (updated via http or modified by user in UI), or if you need to sort or page them - watcher gets called and updates your EventsPreProccessed - and that variable can be formed to be easily used within your ng-repeat.

This isn't ideal since it's not elegant to have presentational logic in the controller.. I know, but that's the only way i know of doing it atm.

Val Redchenko
  • 580
  • 1
  • 8
  • 20
1

I found a possible solution here: angularjs-how-to-get-an-ngrepeat-filtered-result-reference

  1. add custom filter:
app.filter("as", function($parse) {
  return function(value, path) {
    return $parse(path).assign(this, value);
  };
});
  1. Apply filter to the ng-repeat
 <div data-ng-repeat="item in Events  | filter:Filter | orderBy:SortBy:SortDesc | as: 'filtered'">...</div>
  1. filtered array is available as $scope.filtered and can be used for header display. It works perfectly.
Community
  • 1
  • 1
Sergei Rudakov
  • 558
  • 1
  • 4
  • 11