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">
|
src="https://travopti.de/api/v1/regions/{{result.region_id}}/image">
|
||||||
<div class="result-title">
|
<div class="result-title">
|
||||||
<div class="result-name">
|
<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>
|
<span class="result-country">| {{result.country}}</span>
|
||||||
</div>
|
</div>
|
||||||
<app-bookmark-button [region]="result"></app-bookmark-button>
|
<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>
|
<span>{{PROPERTY_VIS_DEF[score.type] ? PROPERTY_VIS_DEF[score.type].unit : ''}}</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td *ngIf="debug">
|
||||||
<div class="cell">
|
<div class="cell">
|
||||||
<span>({{score.score}})</span>
|
<span>({{score.score}})</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -12,6 +12,9 @@ export class ResultComponent implements OnInit {
|
|||||||
@Input()
|
@Input()
|
||||||
result: Result;
|
result: Result;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
debug = false;
|
||||||
|
|
||||||
/** Contains the visual definitions */
|
/** Contains the visual definitions */
|
||||||
readonly PROPERTY_VIS_DEF = REGION_PARAM_VIS;
|
readonly PROPERTY_VIS_DEF = REGION_PARAM_VIS;
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,25 @@
|
|||||||
<span #result></span>
|
<span #result></span>
|
||||||
|
|
||||||
<div *ngIf="results && results.length > 0">
|
<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">
|
<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>
|
||||||
</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 {
|
.result-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@ -3,6 +3,13 @@ import {ActivatedRoute, Router} from '@angular/router';
|
|||||||
import {Result} from '../../interfaces/result.interface';
|
import {Result} from '../../interfaces/result.interface';
|
||||||
import {SearchService} from '../../services/search.service';
|
import {SearchService} from '../../services/search.service';
|
||||||
|
|
||||||
|
interface SortOption {
|
||||||
|
name: string;
|
||||||
|
property: string;
|
||||||
|
descending?: boolean;
|
||||||
|
isScore?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-search',
|
selector: 'app-search',
|
||||||
templateUrl: './search.component.html',
|
templateUrl: './search.component.html',
|
||||||
@ -10,9 +17,20 @@ import {SearchService} from '../../services/search.service';
|
|||||||
})
|
})
|
||||||
export class SearchComponent implements OnInit {
|
export class SearchComponent implements OnInit {
|
||||||
|
|
||||||
|
/** Current base64 encoded query */
|
||||||
queryString: string;
|
queryString: string;
|
||||||
|
/** Current results */
|
||||||
results: Result[];
|
results: Result[];
|
||||||
|
|
||||||
|
/** The property to sort by */
|
||||||
|
sortBy = 'score';
|
||||||
|
/** Sort descending */
|
||||||
|
sortDes = true;
|
||||||
|
/** Available sort options */
|
||||||
|
sortOptions: SortOption[] = [];
|
||||||
|
|
||||||
|
debug = false;
|
||||||
|
|
||||||
@ViewChild('result', {static: false})
|
@ViewChild('result', {static: false})
|
||||||
resultDiv: ElementRef;
|
resultDiv: ElementRef;
|
||||||
|
|
||||||
@ -22,6 +40,7 @@ export class SearchComponent implements OnInit {
|
|||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
this.route.queryParams.subscribe(async params => {
|
this.route.queryParams.subscribe(async params => {
|
||||||
this.queryString = params.q;
|
this.queryString = params.q;
|
||||||
|
this.debug = params.debug || false;
|
||||||
this.results = undefined;
|
this.results = undefined;
|
||||||
|
|
||||||
if (!this.queryString || this.queryString.length === 0) {
|
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.results = await this.ss.executeSearch(this.queryString);
|
||||||
this.resultDiv.nativeElement.scrollIntoView({behavior: 'smooth', block: 'start'});
|
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) {
|
onResultClick(result: Result) {
|
||||||
this.router.navigate(['/region', result.region_id]).catch(console.log);
|
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