Reputation: 151
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
Reputation: 6813
I'd use a regexp to pull the title from the name:
var regex = /((Dr\.|Mr\.|Ms\.|Miss|Mrs\.)\s*)/gmi
objName.replace(regex, '')
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
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.
<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
.
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
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