2

I have list that contain various object. A few objects on this list have a date field (which basically is returned to me as a string from server, not a date object), while for others this field is null.

The requirement I have is to display objects without date at top, and those with date needs to be displayed after them sorted by date field.

Also for objects without date sorting needs to be done alphabetically.

Earlier I was using

$scope.lists.sort(function (a, b) { 
    return new Date(a.date.split("-")[2], a.date.split("-")[1], a.date.split("-")[0]) - new Date(b.date.split("-")[2], b.date.split("-")[1], b.date.split("-")[0]); 
    });

But now with null date fields this would not work. So unable to find anything, I wrote this logic:

{
    var datelists=[];
    var savelists =[];
    $scope.lists.forEach(function (t) {
        if (t.date !== null) {
            datelists.push(t);
        } else {
            savelists.push(t);
        }
    });
    datelists.sort(function (a, b) {
       return new Date(a.date.split("-")[2], a.date.split("-")[1], a.date.split("-")[0]) - new Date(b.date.split("-")[2], b.date.split("-")[1], b.date.split("-")[0]);
    });
    savelists.sort(function (a, b) {
        return a.name - b.name;
    });
    $scope.lists = [];
    $scope.lists = savelists.concat(datelists);
}

I don't like this long method. I am sure there is an elegant way to do this. I would like to know what other alternatives do I have?

Saurabh Tiwari
  • 4,632
  • 9
  • 42
  • 82
  • 1
    how does the date look like? [iso6801](https://en.wikipedia.org/wiki/ISO_8601)? please add some example data. – Nina Scholz May 18 '16 at 06:36
  • sorted alphabetically by what? – Bergi May 18 '16 at 06:43
  • Have a look [here](http://stackoverflow.com/a/29829370/1048572) or [there](http://stackoverflow.com/q/12872211/1048572) – Bergi May 18 '16 at 06:50
  • date as I mentioned in ques is nothing but a string for me like "10-02-2016" – Saurabh Tiwari May 18 '16 at 09:03
  • Again its no ISO format or a date object, so just comparing two dates (Strings) won't work here. Also, only objects with dates nedd to be sorted on date, rest objects will always be on top of them based on their names. I edited question for second comparison – Saurabh Tiwari May 18 '16 at 09:09
  • Also the name field will always be there, regardless of date field – Saurabh Tiwari May 18 '16 at 09:45

3 Answers3

1

To avoid splitting the arrays, sort the entire array on primary and secondary keys of date and text. Usingobj.date and obj.text as example property names holding date and sort text respectively:

function dateCompare( d, e)
{   // code to compare date strings
    // return -1 for date d before e
    //         0 for date d same as e
    //        +1 for date e before d
    // algorithm depends on server date string format but could start

    if( !d)
       return e ? -1 : 0; // d is empty
    if( !e)
       return 1;          // e is empty, d is not
    // ... compare date strings
}


function textCompare(s, t)
{   // code to compare string  values
    // return -1 for s < t
    //         0 for s == t
    //        +1 for t > s

    // algorithms vary according to requirements. 
}

function objCompare( a, b)
{  // return a non zero result of dateCompare, or the result of textCompare:

   return dateCompare(a.date, b.date) || textCompare( a.text, b.text);
}

$scope.lists.sort( objCompare);

outlines how to go about it without getting into application specifics. Convert objCompare into an inline anonymous function with nested date and text comparison support functions (or inline the code) as required to match with existing programming style.

traktor
  • 17,588
  • 4
  • 32
  • 53
0

While sorting you must check if date is null, is undefined or is normal date (not tested)

.sort(function (a, b) {
    // sort alphabetically
    if (typeof a.date == 'undefined' && typeof b.date != 'undefined') {
        return -1;
    } else if (typeof a.date != 'undefined' && typeof b.date == 'undefined') {
        return 1;
    } else if (typeof a.date == 'undefined' && typeof b.date == 'undefined') {
        return a.name.localeCompare(b.name);
    // move null to top
    } else if (a.date == null && b.date != null) {
        return -1;
    } else if (a.date != null && b.date == null) {
        return 1;
    } else if (a.date == null && b.date == null) {
        return 0;

    // both objects has date, sort by date.
    } else {
        var d1 = Date.parse(a.date);
        var d2 = Date.parse(b.date);

        return d1 - d2;
    }
})
Justinas
  • 41,402
  • 5
  • 66
  • 96
0

First, you can convert date to an ISO6801 date string.

If a date is supplied, or a falsy value, which is replaced by an empty string, you could use a String#localeCompare. This sorts empty strings to top.

If the date is the same or both have no date, then its sorted by name.

$scope.lists.sort(function (a, b) {
    function date(s) {
        return s.replace(/(\d{2})-(\d{2})-(\d{4})/g, '$3-$2-$1');
    }

    return (date(a.date) || '').localeCompare(date(b.date) || '') ||
        a.name.localeCompare(b.name);
});
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392