Snsa90
Snsa90

Reputation: 151

AngularJS orderby refining

I have a table of names starting with a title (Mr, Mrs, etc) and dates stored as strings plus some other data.

I am currently sorting it using

<tr dir-paginate="booking in bookingResults | orderBy:sortType:sortReverse | filter:searchPassenger | itemsPerPage: 15">

How could I refine my orderBy to sort names excluding the title (Mr, Mrs, etc) and dates as parsed dates not strings.

What would be best practice here?

EDIT : I don't want to change the names in the model by the way - I want the format to remain "Mr Foo" and "Mr Bar" but when I sort them I want them to act as if they were just "Foo" and "Bar".

EDIT EDIT : AngularJS 1.5.6

Upvotes: 0

Views: 210

Answers (2)

jusopi
jusopi

Reputation: 6813

getting the right data in the right format

title & name

I'd use a regexp to pull the title from the name:

var regex = /((Dr\.|Mr\.|Ms\.|Miss|Mrs\.)\s*)/gmi
objName.replace(regex, '')

date

I'm assuming you're getting either a date object or a standard date string. If it's the latter, just create a Date object via new Date(incomingDateString). Then you can call:

objDate.getTime() //returns epoch in milliseconds

sorting

Some people might dislike this but I hate dirtying up view controllers with methods that NG directives need to use for things like ordering. Instead, I added some ng-flagged properties using ng-init on each row item. Then I can sort based off that. I didn't do it for the date in the example but you could extrapolate and apply.

ng-init w. ng-flagged properties

<tr ng-repeat="row in vc.listData | orderBy:vc.sortKey track by $index"
    ng-init="row.$name = row.name.replace(vc.regexp, '')">

So in other words your objects go from this:

{ 
    name:'Mr. Fred Rogers', 
    date:<date-object> 
}

to this thanks to ng-init:

{ 
    name:'Mr. Fred Rogers', 
    date:<date-object>, 
    $name:'Fred Rogers', 
    $date:1466192224091 
}

And then via your sorting UI, you can set your $scope.sortKey to either $name or $date.

code pen

I made a sample in code pen but I did it with my template which is coffeescript and jade. You can probably figure out what I'm doing.

pen - http://codepen.io/jusopi/pen/aZZjgG?editors=1010

Upvotes: 1

Snsa90
Snsa90

Reputation: 151

Ok, after some research, I found that the easiest solution is upgrading to AngularJS version 1.5.7 which introduces the comparator into the orderBy filter.

So I've changed my repeater to use an order by comparator

<tr dir-paginate="booking in Results | orderBy:Variable:TrueOrFalse:bookingComparator">

Variable is a string which I bound to the table headings so you can change the order by key, TrueOrFalse is a boolean which alternates between ascending and descending if you click the table heading and bookingComparator is my actual comparator.

My booking comparator looks like this

   $scope.bookingComparator = function (a, b) {
        var getTitle = /((Mrs|Mr|Mstr|Miss|Dr)\s*)/g;
        var isDate = /(-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-)/g

        if (getTitle.test(a.value)) {                
            var aName = a.value, bName = b.value;
            return aName.replace(getTitle, '') < bName.replace(getTitle, '') ? -1 : 1
        }

        if (isDate.test(a.value)) {
            var aDate = new Date(a.value), bDate = new Date(b.value);
            return aDate.getTime() < bDate.getTime() ? -1 : 1
        }

        return a.index < b.index ? -1 : 1
    }

The comparator is basically a function acting like the javascript .sort() method.

If the value contains a title (Mr, Mrs, etc) it is a name so I strip the titles and compare the actual names regardless of title.

If the variable matches a -Month- pattern, it's a date string and I compare the parsed date objects.

Hope this is helpful to someone, took me a while to figure out. I'm open to suggestions if you think there's a better way of doing this, and feel free to post an answer for people who want to use AngularJS =< 1.5.6

Upvotes: 0

Related Questions