Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GroupBy + OrderBy not working #57

Closed
jtomek opened this issue Nov 30, 2014 · 16 comments

Comments

Projects
None yet
7 participants
@jtomek
Copy link

commented Nov 30, 2014

Hi guys,

I can't get OrderBy to work with GroupBy.

ng-repeat="(key, value) in memories | groupBy: 'groupDate' | orderBy : '-groupDate'

orderBy does not work.

groupDate is a normal date (2014/11/29)
I also tried using value.data.groupDate[0]; Not working too.

Nothing seems to change the order.

Could you please advice?

Thanks and best regards,
Jakub

@a8m

This comment has been minimized.

Copy link
Owner

commented Dec 1, 2014

Hi @jtomek , see issue #26
quote: orderBy must be the last filter in the chaining (when you apply filter to the result of another filter).
But, groupBy return an object, and orderBy expect array as an arguments.
So, you can do something like that:

$scope.groups = [
    { category: 'alpha', id: 2 },
    { category: 'beta',  id: 3 }, 
    { category: 'gamma', id: 0 },
    { category: 'alpha', id: 4 },
    { category: 'beta',  id: 5 }, 
    { category: 'gamma', id: 1 }
   ];
  // retrieves the min 'id' of a collection, used for the group ordering.
  // you can use lodash instead. e.g: _.min(arr, 'id') 
  $scope.min = function(arr) {
    return $filter('min')
      ($filter('map')(arr, 'id'));
  }
 <ul ng-repeat="group in groups | groupBy:'category' | toArray:true | orderBy:min">
    <!-- print the group name -->
    <li>{{ group.$key }}</li>
    <!-- iterate over the group members and order each group by id -->
    <li ng-repeat="item in group | orderBy:'id'">
      {{ item }}
    </li>
</ul>

RESULT:

- gamma
  - {"category":"gamma","id":0}
  - {"category":"gamma","id":1}
- alpha
  - {"category":"alpha","id":2}
  - {"category":"alpha","id":4}
- beta
  - {"category":"beta","id":3}
  - {"category":"beta","id":5}
@jtomek

This comment has been minimized.

Copy link
Author

commented Dec 1, 2014

Thank you very much for your reply!

I have already seen this entry. I think it does not fit to my problem.

All of my entries have a created_at date. I group these entries by month and year. I have for example the following groups:

Raw Input (random)
  • November 14,
  • October 13
  • December 14,
  • November 13,

I would like to get (newest groups first)

Expected Output
  • December 14
  • November 14
  • November 13
  • October 13

I understand that I can format the date in one way (2014/12, 2014/11, 2013/11, 2013/10) for the grouping and I can then format the view in a more readable way (December 14), that is no problem. So right now, the grouping is ordered like this:

Current Output
  • 2013/10
  • 2013/11
  • 2014/11
  • 2014/12

I would like to order the groups by -groupDate (reverse).

In future, I may want to add additional possibilities of grouping, such as numbers, Group names.

How to achieve this functionality?

I look Forward your reply,
Jakub

@jtomek

This comment has been minimized.

Copy link
Author

commented Dec 1, 2014

I figured out that the problem is connected to Masonry. When I call toArray, the view starts "blinking". Scope appears and disappears in 100 ms intervals. I am not quite sure how to solve it nicely.

Nevertheless, I came up with a workaround solution :-\

It is possible to do simple subscrations to reverse the native sorting.

I subtract the year of an entry from the current year. I subtract the month of the entry from the 12.

2014: 2014 - 2014 = 0, thus first.
2014-2013 = 1 gets second.

For months... I use max 12 - month of th entry.
For 2014 December: 2014-2014 and 12-12 = 0 0
For 2014 November: 2014-2014 and 12-11 = 0 1
For 2013 December: 2014-2013 and 12-12 = 1 0

Sorted alphabetically, I get it correct.

I am sorry, but I can't unfortunately get it work differently. I have already spent two days on this problem :-\

@a8m

This comment has been minimized.

Copy link
Owner

commented Dec 2, 2014

@jtomek can you please provide some fiddle/jsbin example?

@a8m a8m closed this Dec 2, 2014

@a8m a8m reopened this Dec 2, 2014

@RouR

This comment has been minimized.

Copy link

commented Dec 9, 2014

@a8m please add the example to documentation

@a8m

This comment has been minimized.

Copy link
Owner

commented Dec 9, 2014

Hi @RouR
Please, feel free to PR.

@RouR

This comment has been minimized.

Copy link

commented Dec 9, 2014

@a8m

This comment has been minimized.

Copy link
Owner

commented Dec 9, 2014

@RouR please, take a look on this example: jsbin

@RouR

This comment has been minimized.

Copy link

commented Dec 9, 2014

thank you very much!

@a8m

This comment has been minimized.

Copy link
Owner

commented Dec 9, 2014

@RouR Cheers.

@dyorg

This comment has been minimized.

Copy link

commented Dec 9, 2014

Can I contribute?

I replace _groupBy function to work with native orderBy. that's better, isn't it?

return filterWatcher.isMemoized('groupBy', arguments) ||
        filterWatcher.memoize('groupBy', arguments, this,
          _groupBy(collection, property));

function _groupBy (collection, key) {       
        var result = {};
        var indexes;
    indexes = [];

    forEach(collection, function(item) {
            var group_name = item[key];
            var index = indexes.indexOf(group_name);

            if (index == -1) {
                    index = indexes.push(group_name) - 1;
                    result[index] = {};
                    result[index].group_name = group_name;
                    result[index].items = [];
            }

            result[index].items.push(item);
     });
     return result;
};
<ul ng-repeat="task_group in tasks | orderBy : 'date' | groupBy : 'date'">
    <!-- print the group name -->
    <li>{{ task_group.group_name}}</li>
    <!-- iterate over the group tasks and order each group by name -->
    <li ng-repeat="task in task_group.items | orderBy:'name'">
      {{ task }}
    </li>
</ul>
@dyorg

This comment has been minimized.

Copy link

commented Dec 10, 2014

GroupBy filter complete with a improve

angular.module('a8m.group-by', [ 'a8m.filter-watcher' ])
  .filter('groupBy', [ '$parse', 'filterWatcher', function ( $parse, filterWatcher ) {
    return function (collection, property) {

      if(!isObject(collection) || isUndefined(property)) {
        return collection;
      }

      return filterWatcher.isMemoized('groupBy', arguments) ||
        filterWatcher.memoize('groupBy', arguments, this,
          _groupBy(collection, property));

      /**
       * groupBy function
       * @param collection
       * @param getter
       * @returns {{}}
       */
      function _groupBy (collection, key) {
            var result = {};
            var indexes;
            indexes = [];

            forEach(collection, function(item) {
                var group_name = item[key];
                var index = indexes.indexOf(group_name);

                if (index == -1) {
                    index = pad(indexes.push(group_name) - 1, 4);
                    result[index] = {};
                    result[index].group_name = group_name;
                    result[index].items = [];
                } else {
                    index = pad(index, 4);
                }

                result[index].items.push(item);
            });
            return result;
      };

      /**
       * padding function
       * @param number
       * @param length
       * @returns string
       */
      function pad (number, length) {
            var str = '' + number;
            while (str.length < length) {
                str = '0' + str;
            }
            return str;
      }
    };
 }]);
@evilaliv3

This comment has been minimized.

Copy link

commented Aug 22, 2015

@a8m : i've implemented the solution that you suggest in #57 (comment) but it appears to me to trigher a 100% cpu as probably the digest loop never finish. is there any alternative?

@evilaliv3

This comment has been minimized.

Copy link

commented Aug 22, 2015

ok it was my fault as im using it with nested forms inputs so that i've to benefit of the onetime binding (::) in order to evaluate it only once.

@rkingon

This comment has been minimized.

Copy link

commented Jul 28, 2016

I found the performance on the | toArray: true | orderBy: customMappingFunction method to be terrible. I came up with a solution that keeps performance up and produces the correct result -- (although it does seem a bit odd!)

<div ng-repeat="(key, results) in allResults | groupBy: '-someKey' )">
    <h3>{{ key | ltrim: '-' }}</h3>
    <ul>
        <li ng-repeat="result in results">
            {{ result }}
        </li>
    </ul>
</div>

For whatever reason, adding the - does force the groupBy to sort correctly, but it also adds it to the key, so we can just remove it!

@chenyilei

This comment has been minimized.

Copy link

commented Apr 15, 2019

Hi @jtomek , see issue #26
quote: orderBy must be the last filter in the chaining (when you apply filter to the result of another filter).
But, groupBy return an object, and orderBy expect array as an arguments.
So, you can do something like that:

$scope.groups = [
    { category: 'alpha', id: 2 },
    { category: 'beta',  id: 3 }, 
    { category: 'gamma', id: 0 },
    { category: 'alpha', id: 4 },
    { category: 'beta',  id: 5 }, 
    { category: 'gamma', id: 1 }
   ];
  // retrieves the min 'id' of a collection, used for the group ordering.
  // you can use lodash instead. e.g: _.min(arr, 'id') 
  $scope.min = function(arr) {
    return $filter('min')
      ($filter('map')(arr, 'id'));
  }
 <ul ng-repeat="group in groups | groupBy:'category' | toArray:true | orderBy:min">
    <!-- print the group name -->
    <li>{{ group.$key }}</li>
    <!-- iterate over the group members and order each group by id -->
    <li ng-repeat="item in group | orderBy:'id'">
      {{ item }}
    </li>
</ul>

RESULT:

- gamma
  - {"category":"gamma","id":0}
  - {"category":"gamma","id":1}
- alpha
  - {"category":"alpha","id":2}
  - {"category":"alpha","id":4}
- beta
  - {"category":"beta","id":3}
  - {"category":"beta","id":5}

good for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.