Add search result sorting
This commit is contained in:
parent
e948243417
commit
f9157e8e61
@ -3,7 +3,7 @@
|
||||
src="https://travopti.de/api/v1/regions/{{result.region_id}}/image">
|
||||
<div class="result-title">
|
||||
<div class="result-name">
|
||||
<span class="result-name">{{result.name}}</span>
|
||||
<span class="result-name">{{result.name}}<span *ngIf="debug"> ({{result.score}})</span></span>
|
||||
<span class="result-country">| {{result.country}}</span>
|
||||
</div>
|
||||
<app-bookmark-button [region]="result"></app-bookmark-button>
|
||||
@ -28,7 +28,7 @@
|
||||
<span>{{PROPERTY_VIS_DEF[score.type] ? PROPERTY_VIS_DEF[score.type].unit : ''}}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<td *ngIf="debug">
|
||||
<div class="cell">
|
||||
<span>({{score.score}})</span>
|
||||
</div>
|
||||
|
||||
@ -12,6 +12,9 @@ export class ResultComponent implements OnInit {
|
||||
@Input()
|
||||
result: Result;
|
||||
|
||||
@Input()
|
||||
debug = false;
|
||||
|
||||
/** Contains the visual definitions */
|
||||
readonly PROPERTY_VIS_DEF = REGION_PARAM_VIS;
|
||||
|
||||
|
||||
@ -3,9 +3,25 @@
|
||||
<span #result></span>
|
||||
|
||||
<div *ngIf="results && results.length > 0">
|
||||
<h2>Results ({{results.length}}):</h2>
|
||||
<div class="result-header">
|
||||
<span class="title">Results ({{results.length}})</span>
|
||||
<div class="sorting">
|
||||
<button (click)="sortDes = !sortDes; onSortDirChange()" mat-icon-button>
|
||||
<mat-icon>{{sortDes ? 'arrow_downwards' : 'arrow_upwards'}}</mat-icon>
|
||||
</button>
|
||||
<mat-form-field>
|
||||
<mat-label>Sort by</mat-label>
|
||||
<mat-select (selectionChange)="onSortChange()" [(ngModel)]="sortBy">
|
||||
<mat-option *ngFor="let option of sortOptions" [value]="option.property">
|
||||
{{option.name|translate}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<div class="result-container">
|
||||
<app-result (click)="onResultClick(result)" *ngFor="let result of results" [result]="result"></app-result>
|
||||
<app-result (click)="onResultClick(result)" *ngFor="let result of results" [debug]="debug"
|
||||
[result]="result"></app-result>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -8,6 +8,24 @@
|
||||
}
|
||||
}
|
||||
|
||||
.result-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 1rem 0;
|
||||
|
||||
.title {
|
||||
flex: 1 1 auto;
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.sorting {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.result-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@ -3,6 +3,13 @@ import {ActivatedRoute, Router} from '@angular/router';
|
||||
import {Result} from '../../interfaces/result.interface';
|
||||
import {SearchService} from '../../services/search.service';
|
||||
|
||||
interface SortOption {
|
||||
name: string;
|
||||
property: string;
|
||||
descending?: boolean;
|
||||
isScore?: boolean;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-search',
|
||||
templateUrl: './search.component.html',
|
||||
@ -10,9 +17,20 @@ import {SearchService} from '../../services/search.service';
|
||||
})
|
||||
export class SearchComponent implements OnInit {
|
||||
|
||||
/** Current base64 encoded query */
|
||||
queryString: string;
|
||||
/** Current results */
|
||||
results: Result[];
|
||||
|
||||
/** The property to sort by */
|
||||
sortBy = 'score';
|
||||
/** Sort descending */
|
||||
sortDes = true;
|
||||
/** Available sort options */
|
||||
sortOptions: SortOption[] = [];
|
||||
|
||||
debug = false;
|
||||
|
||||
@ViewChild('result', {static: false})
|
||||
resultDiv: ElementRef;
|
||||
|
||||
@ -22,6 +40,7 @@ export class SearchComponent implements OnInit {
|
||||
async ngOnInit() {
|
||||
this.route.queryParams.subscribe(async params => {
|
||||
this.queryString = params.q;
|
||||
this.debug = params.debug || false;
|
||||
this.results = undefined;
|
||||
|
||||
if (!this.queryString || this.queryString.length === 0) {
|
||||
@ -31,10 +50,53 @@ export class SearchComponent implements OnInit {
|
||||
|
||||
this.results = await this.ss.executeSearch(this.queryString);
|
||||
this.resultDiv.nativeElement.scrollIntoView({behavior: 'smooth', block: 'start'});
|
||||
|
||||
this.sortOptions = [
|
||||
{name: 'Relevance', property: 'score', descending: true},
|
||||
{name: 'Name', property: 'name'}
|
||||
];
|
||||
|
||||
if (this.results.length > 0) {
|
||||
this.results[0].scores.forEach(({type}) => {
|
||||
this.sortOptions.push({name: type, property: type, isScore: true});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
onResultClick(result: Result) {
|
||||
this.router.navigate(['/region', result.region_id]).catch(console.log);
|
||||
}
|
||||
|
||||
onSortDirChange() {
|
||||
const option = this.sortOptions.find(i => i.property === this.sortBy);
|
||||
this.sortResults(option, this.sortDes);
|
||||
}
|
||||
|
||||
onSortChange() {
|
||||
const option = this.sortOptions.find(i => i.property === this.sortBy);
|
||||
this.sortDes = option.descending;
|
||||
this.onSortDirChange();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the results array by the given property.
|
||||
* @param property The property to sort by
|
||||
* @param isScore If the property is in scores
|
||||
* @param descending Sort descending instead of ascending
|
||||
*/
|
||||
private sortResults({property, isScore}: SortOption, descending: boolean) {
|
||||
this.results = this.results.sort(isScore ? sortByScore : sortByPorperty);
|
||||
|
||||
function sortByPorperty(a: Result, b: Result): number {
|
||||
const result = a[property] > b[property] ? 1 : -1;
|
||||
return descending ? result * -1 : result;
|
||||
}
|
||||
|
||||
function sortByScore(a: Result, b: Result): number {
|
||||
const result = a.scores.find(i => i.type === property).value > b.scores.find(i => i.type === property).value ? 1 : -1;
|
||||
return descending ? result * -1 : result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user