Reputation: 15196
I have a list/table of persons, that i can sort by firstname, lastname, etc.
When i click on a heading (say firstname) it route with a querystring parameter
?sort=firstname
, and if i click it again it will change the param to
?sort=firstname-desc
. At the same time, i need an icon to show an up or down arrow next to the parameter, indicating ascending or descending sorting. This is a pretty standard sorting scenario.
My current template looks like this:
<div class="heading">
First name
<a [routerLink] [queryParams]="sortParams('firstname')">
<img src="assets/icons/icon-sort-down.svg" class="icon-normal" [class.flip]="showFlip('firstname')">
</a>
</div>
This works fine, because I have some logic in the component to handle sortParams
and showFlip
but i would like to simplify it, so i can easily add the same logic to multiple fields, and on multiple views, without the need for the extra duplicated component logic.
Creating a directive seems the way to go, but when i create directives, i normally only modify dom attributes using the @HostBinding
. How would it be possible to write a directive (call it sorting) that would allow me to define the template like this instead:
<div class="heading">
First name
<a [sorting]="'firstname'"></a>
</div>
The directive would need to modify the a tag to include routerLink
and queryParams
, as well as add some non-static template content. I know i can inject ViewContainerRef
in my directive, but from there, my directive knowledge needs some help.
Upvotes: 1
Views: 3588
Reputation: 15196
Ok so i figured out writing a directive to solve this problem is a bad idea. What i really need is just a component to wrap the logic.
I ended up with almost the markup/template i wanted. In reality i could have made it excatly like i set it out to be, but decided against the component doing the router parsing, and instead parse the querystring sort parameter to the component for it to do the final processing of it.
<div class="heading">
First name
<fd-sorting-header [fieldName]="'firstname'" [sort]="sort"></fd-sorting-header>
</div>
So I created a component that does the parsing of the sort querystring and setting of the routerLink/queryParams. The components template ended up like this:
<a [routerLink] [queryParams]="sortParams"><img src="assets/icons/icon-sort-down.svg" class="icon-normal" [class.flip]="showFlip"></a>
And a simple class like this:
export class SortingHeaderComponent {
public sortParams: any;
public showFlip: boolean;
@Input('fieldName') fieldName: string;
@Input('sort')
set sort(sort: string) {
const [column, dir] = (sort || '').split('-');
const direction = (dir && dir.toLowerCase() === 'desc') ? 'desc' : 'asc';
this.showFlip = column === this.fieldName && direction !== 'desc';
this.sortParams = { sort: this.fieldName + ((this.showFlip) ? '-desc' : '') };
}
constructor() { }
}
Upvotes: 1
Reputation: 5889
Would please try this:
import {Directive, Input} from '@angular/core';
import {YourSortingService} from 'YouServiceFileLocation';
@Directive({
selector:'[sorting]'
})
export SortingDirective{
@Input() sortingQueryString:string;
constructor(private sortingService:YourSortingService){}
@HostBinding('click')
private onClick(){
//On click on the <a> tag
this.sortingService.get(`url?sort=${this.sortingQueryString}`);
}
}
And you can use it like this:
<div class="heading">
First name
<a sorting [sortingQueryString]="'firstname'"></a>
</div>
Upvotes: 1