1

How do you sort the following sample array by the dt (date) property of each object?

$scope.arr = [ 
    {test: 1, dt: 'March, 10 2016 14:55:00'},
    {test: 2, dt: 'February, 10 2013 14:25:00'},
    {test: 3, dt: 'August, 10 2015 14:55:00'} 
];

I tried _.sortBy($scope.arr, 'dt'), but that treats the date as a string and only does the sorting alphabetically. I tried converting the date into unix time and that actually complicated things as my real code is more complex.

Do you have any other suggestions of sorting the above in a descending order and show the result in a dropdown?

pro
  • 779
  • 5
  • 24
  • I think it's a duplicate of [this](http://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value-in-javascript), but I'll reopen it as it's not really sorting "by strings", but by dates. Maybe someone else has a more appropriate duplicate, because this has surely been asked before. – adeneo Aug 09 '16 at 16:43
  • Anyway, you have to parse the dates to valid date objects, and then just do `$scope.arr.sort( (a,b) => { return parse(a) - parse(b) });` etc. – adeneo Aug 09 '16 at 16:44
  • can you convert to ints and then compare? Date.parse("March 21, 2012"); – brad Aug 09 '16 at 16:45
  • http://stackoverflow.com/questions/10238127/sorting-by-date-with-underscore-js-or-just-plain-js ? That answer suggests creating a sort function and converting the string to a date. – Jason P Aug 09 '16 at 16:45
  • The best thing you can do is create and array of months using keys as numbers and use that to compare with the array you have above. – Robert Rocha Aug 09 '16 at 16:46
  • See this related answer: **[Sort Javascript Object Array By Date](https://stackoverflow.com/questions/10123953/sort-javascript-object-array-by-date/26759127#26759127)** – jherax Aug 09 '16 at 16:54

5 Answers5

6

You can sort with this call back which uses the Date equivalents for comparing:

$scope.arr.sort( (a, b) => new Date(a.dt) - new Date(b.dt) );

$scope = {}; // for the snippet to work
$scope.arr = [ 
    {test: 1, dt: 'March, 10 2016 14:55:00'},
    {test: 2, dt: 'February, 10 2013 14:25:00'},
    {test: 3, dt: 'August, 10 2015 14:55:00'} 
];

$scope.arr.sort( (a, b) => new Date(a.dt) - new Date(b.dt) );

console.log($scope.arr);
trincot
  • 211,288
  • 25
  • 175
  • 211
4

Suffice it to sort on the second property casted as a Date Object :

var arr = [
    {test: 1, dt: 'March, 10 2016 14:55:00'},
    {test: 2, dt: 'February, 10 2013 14:25:00'},
    {test: 3, dt: 'August, 10 2015 14:55:00'}
];

arr.sort((a,b) => new Date(b.dt) - new Date(a.dt));
console.log(arr);
Trasiva
  • 484
  • 14
  • 27
kevin ternet
  • 3,779
  • 2
  • 14
  • 23
2

As those aren't really valid dates, even if they can be parsed by some browser, you'd generally want to parse them properly and pass in numbers to new Date, then sort based on the date objects etc.

var months = [
  'January',
  'February',
  'March',
  'April',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December'
];

function parse(dt) {
  var p = dt.replace(/(\,|\:)/g, ' ').split(/\s+/).filter((x) => {
    return x.trim().length > 0;
  });
  return new Date(p[2], months.indexOf(p[0]), p[1], p[3], p[4], p[5]);
}
var $scope = {}; // for demonstration ...

$scope.arr = [{
  test: 1,
  dt: 'March, 10 2016 14:55:00'
}, {
  test: 2,
  dt: 'February, 10 2013 14:25:00'
}, {
  test: 3,
  dt: 'August, 10 2015 14:55:00'
}];

$scope.arr.sort((a, b) => {
  return parse(b.dt) - parse(a.dt);
});

document.body.innerHTML = '<pre>' + JSON.stringify($scope.arr, 0, 4) + '</pre>';
adeneo
  • 293,187
  • 26
  • 361
  • 361
0

You can solve it via multiple ways. Either you change the format of the date to get back something like "YYYY-MM-DDThh:mm:ss.sTZD" and then use orderBy to leverage the angular order by. Else you can loop and sort it manually with use of moment library.

Something like this

angular.forEach($scope.arr, function(o){ o.dt = new Date(o.dt); });

and then user orderBy for sorting.

Jayesh
  • 110
  • 1
  • 7
0

A combination of Angular Custom Filter and the orderBy filter can achieve this. This will also allow for further custom formatting.

Updated: Now shows adding new dates and ordering by any field.

angular.module("app", ['core']);

angular.module("app").controller("TestCtrl", function($scope) {

  $scope.arr = [{
    test: 1,
    dt: new Date('March, 10 2016 14:55:00')
  }, {
    test: 2,
    dt: new Date('February, 10 2013 14:25:00')
  }, {
    test: 3,
    dt: new Date('August, 10 2015 14:55:00')
  }];

  $scope.addDate = function() {
    var lastIndex = $scope.arr[$scope.arr.length - 1].test;
    $scope.arr.push({
      test: lastIndex + 1,
      dt: new Date($scope.newDate)
    });
  }

});

angular.module("core", []);
angular.module("core").filter("format", function(dateFilter) {
  return function(input) {
    if (input instanceof Date)
      return dateFilter(input, 'medium');
    return input;
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>

<body ng-app="app">
  <div ng-controller="TestCtrl">
    <input type="text" ng-model="newDate">
    <button ng-click="addDate()">Add Date</button>
    <br/>OrderBy Field:
    <input type="text" ng-model="orderField">

    <table>
      <thead>
        <th ng-repeat="(key,val) in arr[0]">
          {{key}}
        </th>
      </thead>
      <tbody>
        <tr ng-repeat="o in arr | orderBy:orderField">
          <td ng-repeat="(key,val) in o">{{val | format}}</td>
        </tr>
      </tbody>
    </table>
  </div>
</body>
10100111001
  • 1,712
  • 1
  • 9
  • 7