table sorting working

This commit is contained in:
Evert Prants 2020-11-08 11:34:10 +02:00
parent c3f0ffe190
commit 46065fc745
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
14 changed files with 150 additions and 40 deletions

View File

@ -1,6 +0,0 @@
import { IPerson } from './person'
export interface IAPIResponse {
stats: any;
list: IPerson[];
}

View File

@ -11,6 +11,7 @@ import { ListComponent } from './list/list.component';
import { ListPaginateComponent } from './list-paginate/list-paginate.component'; import { ListPaginateComponent } from './list-paginate/list-paginate.component';
import { ListService } from './list.service'; import { ListService } from './list.service';
import { GenderPipe } from './gender.pipe'; import { GenderPipe } from './gender.pipe';
import { CustomSortPipe } from './custom-sort.pipe';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -20,12 +21,13 @@ import { GenderPipe } from './gender.pipe';
ListPageComponent, ListPageComponent,
ListComponent, ListComponent,
ListPaginateComponent, ListPaginateComponent,
GenderPipe GenderPipe,
CustomSortPipe,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
AppRoutingModule, AppRoutingModule,
HttpClientModule HttpClientModule,
], ],
providers: [ providers: [
], ],

View File

@ -1 +1 @@
<p>article-page works!</p> <app-article></app-article>

View File

@ -1,5 +1,7 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
// This is a router component for the article.
@Component({ @Component({
selector: 'app-article-page', selector: 'app-article-page',
templateUrl: './article-page.component.html', templateUrl: './article-page.component.html',

View File

@ -0,0 +1,8 @@
import { CustomSortPipe } from './custom-sort.pipe';
describe('CustomSortPipe', () => {
it('create an instance', () => {
const pipe = new CustomSortPipe();
expect(pipe).toBeTruthy();
});
});

View File

@ -0,0 +1,19 @@
import { Pipe, PipeTransform } from '@angular/core';
import { Sort } from './sort'
const sorter = new Sort();
// This is a sorting pipe for the list of people.
// I couldn't come up with a better way of doing it at the moment.
@Pipe({
name: 'customSort'
})
export class CustomSortPipe implements PipeTransform {
transform(value: Array<any>, field: string, direction: number): Array<any> {
if (direction === 0 || field == null) {
return value;
}
return sorter.sort(value.slice(), field, direction);
}
}

View File

@ -1,5 +1,7 @@
import { Pipe, PipeTransform } from '@angular/core'; import { Pipe, PipeTransform } from '@angular/core';
// This is a simple pipe for formatting the gender
@Pipe({ @Pipe({
name: 'gender' name: 'gender'
}) })

View File

@ -1,6 +1,8 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; import { ActivatedRoute } from '@angular/router';
// This is a router component for the list of people.
@Component({ @Component({
selector: 'app-list-page', selector: 'app-list-page',
templateUrl: './list-page.component.html', templateUrl: './list-page.component.html',

View File

@ -16,11 +16,17 @@ export class ListPaginateComponent {
constructor(private router: Router) { } constructor(private router: Router) { }
public get pageNums(): number[] { public get pageNums(): number[] {
// This function calculates the buttons for the pagination so that the
// current page number is always in the center unless it is near the beginning
// or the end.
const starti = Math.min(Math.max(this.page - 2, 1), this.pages - 4); const starti = Math.min(Math.max(this.page - 2, 1), this.pages - 4);
return [...Array(5)].map((p, i) => starti + i); return [...Array(5)].map((p, i) => starti + i);
} }
public navigate(num: number): void { public navigate(num: number): void {
this.router.navigate(['/list'], { queryParams: { page: Math.min(Math.max(num, 1), this.pages) }}); // This function navigates to a page number that is clamped
this.router.navigate(['/list'], { queryParams: {
page: Math.min(Math.max(num, 1), this.pages),
} });
} }
} }

View File

@ -1,18 +1,18 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs' import { Observable } from 'rxjs'
import { IAPIResponse } from './api-response'
// This is the service file for the API request
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
}) })
export class ListService { export class ListService {
private listUrl = 'http://midaiganes.irw.ee/api/list'; private listUrl = 'http://midaiganes.irw.ee/api/list?limit=100';
constructor(private http: HttpClient) { } constructor(private http: HttpClient) { }
public getList(limit: number = 10, offset: number = 0): Observable<IAPIResponse> { public getList(): Observable<any> {
const url = `${this.listUrl}?offset=${offset}&limit=${limit}`; return this.http.get<any>(this.listUrl);
return this.http.get<IAPIResponse>(url);
} }
} }

View File

@ -1,12 +1,57 @@
<table> <table>
<thead> <thead>
<th>Eesnimi</th> <th (click)="setSort('firstname')" class="clickable">Eesnimi
<th>Perekonnanimi</th> <ng-container *ngIf="sortBy === 'firstname';else default_sort">
<th>Sugu</th> <ng-container [ngSwitch]="sortDir">
<th>Sünnikuupäev</th> <i *ngSwitchCase=-1>^</i>
<th>Telefon</th> <i *ngSwitchCase=1>v</i>
<i *ngSwitchDefault>|</i>
</ng-container>
</ng-container>
<ng-template #default_sort><i>|</i></ng-template>
</th>
<th (click)="setSort('surname')" class="clickable">Perekonnanimi
<ng-container *ngIf="sortBy === 'surname';else default_sort">
<ng-container [ngSwitch]="sortDir">
<i *ngSwitchCase=-1>^</i>
<i *ngSwitchCase=1>v</i>
<i *ngSwitchDefault>|</i>
</ng-container>
</ng-container>
<ng-template #default_sort><i>|</i></ng-template>
</th>
<th (click)="setSort('sex')" class="clickable">Sugu
<ng-container *ngIf="sortBy === 'sex';else default_sort">
<ng-container [ngSwitch]="sortDir">
<i *ngSwitchCase=-1>^</i>
<i *ngSwitchCase=1>v</i>
<i *ngSwitchDefault>|</i>
</ng-container>
</ng-container>
<ng-template #default_sort><i>|</i></ng-template>
</th>
<th (click)="setSort('date')" class="clickable">Sünnikuupäev
<ng-container *ngIf="sortBy === 'date';else default_sort">
<ng-container [ngSwitch]="sortDir">
<i *ngSwitchCase=-1>^</i>
<i *ngSwitchCase=1>v</i>
<i *ngSwitchDefault>|</i>
</ng-container>
</ng-container>
<ng-template #default_sort><i>|</i></ng-template>
</th>
<th (click)="setSort('phone')" class="clickable">Telefon
<ng-container *ngIf="sortBy === 'phone';else default_sort">
<ng-container [ngSwitch]="sortDir">
<i *ngSwitchCase=-1>^</i>
<i *ngSwitchCase=1>v</i>
<i *ngSwitchDefault>|</i>
</ng-container>
</ng-container>
<ng-template #default_sort><i>|</i></ng-template>
</th>
</thead> </thead>
<ng-container *ngFor="let person of people"> <ng-container *ngFor="let person of people | customSort:sortBy:sortDir | slice:startIndex:endIndex;">
<tr (click)="selectPerson(person)"> <tr (click)="selectPerson(person)">
<td>{{ person.firstname }}</td> <td>{{ person.firstname }}</td>
<td>{{ person.surname }}</td> <td>{{ person.surname }}</td>

View File

@ -1,20 +1,21 @@
import { Component, OnInit, OnChanges, SimpleChanges, Input } from '@angular/core'; import { Component, OnInit, SimpleChanges, Input } from '@angular/core';
import { ListService } from '../list.service' import { ListService } from '../list.service'
import { IPerson } from '../person' import { IPerson } from '../person'
import { IAPIResponse } from '../api-response'
// This component is for listing the people
@Component({ @Component({
selector: 'app-list', selector: 'app-list',
templateUrl: './list.component.html', templateUrl: './list.component.html',
styleUrls: ['./list.component.styl'] styleUrls: ['./list.component.styl']
}) })
export class ListComponent implements OnInit, OnChanges { export class ListComponent implements OnInit {
public people: IPerson[]; public people: IPerson[];
private selected: IPerson; private selected: IPerson;
private sortBy: string; public sortBy: string;
private sortDir: number; public sortDir = 0;
@Input() @Input()
public page = 1; public page = 1;
@ -23,28 +24,42 @@ export class ListComponent implements OnInit, OnChanges {
constructor(private listService: ListService) { } constructor(private listService: ListService) { }
ngOnChanges(changes: SimpleChanges): void {
if (changes.page) {
this.getList();
}
}
ngOnInit(): void { ngOnInit(): void {
this.getList(); this.getList();
} }
private getList(): void { public get startIndex(): number {
const offset = this.perPage * this.page; // First argument to array slicer
this.listService.getList(this.perPage, offset).subscribe( return (this.page - 1) * this.perPage;
(data) => this.updateList(data));
} }
private updateList(data: IAPIResponse): void { public get endIndex(): number {
this.people = data.list; // Second argument to array slicer
// this.pages = data.stats.total / this.perPage return this.startIndex + this.perPage;
}
public setSort(field: string): void {
// Reset the sorting if it is a new field
if (this.sortBy !== field) {
this.sortDir = 0;
}
this.sortBy = field;
this.sortDir++;
// Loop back to descending sort
if (this.sortDir === 2) {
this.sortDir = -1;
}
}
private getList(): void {
this.listService.getList().subscribe(
(data) => this.people = data.list);
} }
private selectPerson(person: IPerson): void { private selectPerson(person: IPerson): void {
// Select a person to show the details of
if (this.selected === person) { if (this.selected === person) {
this.selected = null; this.selected = null;
return; return;

View File

@ -7,4 +7,4 @@ export interface IPerson {
phone: string; phone: string;
image: string[]; image: string[];
intro: string; intro: string;
}; }

15
src/app/sort.ts Normal file
View File

@ -0,0 +1,15 @@
// This is a simple encapsulation class for the Collator used in sorting.
export class Sort {
private collator = new Intl.Collator('et', {
numeric: true,
sensitivity: 'base',
});
constructor() { }
public sort(value: Array<any>, property: string, order: number, type = ''): Array<any> {
return value.sort((a, b) => this.collator.compare(a[property], b[property]) * order);
}
}