fix: apply filters only on refresh

This commit is contained in:
bisco
2026-06-03 23:24:03 +02:00
parent 2c7ec7383b
commit f8de0e644a
4 changed files with 18 additions and 34 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ The initial schema stores:
- per-season averages, totals, and advanced metrics;
- per-game logs for best and worst performance views.
The Angular dashboard applies live filter updates with a short debounce, quick position/league chips, local stat sorting, summary metrics, and a persistent profile panel on desktop.
The Angular dashboard applies filters only when the user refreshes the result set, then supports local stat sorting, summary metrics, and an open/close profile panel on desktop.
## External Integrations
+6 -8
View File
@@ -26,49 +26,47 @@
<input
type="search"
[(ngModel)]="filters.q"
(ngModelChange)="onFilterChange()"
placeholder="Name, role, team, nationality"
>
</label>
<label>
Position
<select [(ngModel)]="filters.position" (ngModelChange)="onFilterChange()">
<select [(ngModel)]="filters.position">
<option value="">Any</option>
<option *ngFor="let position of positions" [value]="position">{{ position }}</option>
</select>
</label>
<label>
Role
<select [(ngModel)]="filters.role" (ngModelChange)="onFilterChange()">
<select [(ngModel)]="filters.role">
<option value="">Any</option>
<option *ngFor="let role of roles" [value]="role">{{ role }}</option>
</select>
</label>
<label>
League
<select [(ngModel)]="filters.league" (ngModelChange)="onFilterChange()">
<select [(ngModel)]="filters.league">
<option value="">Any</option>
<option *ngFor="let league of leagues" [value]="league">{{ league }}</option>
</select>
</label>
<label>
Min PPG
<input type="number" [(ngModel)]="filters.minPoints" (ngModelChange)="onFilterChange()" min="0" step="0.1">
<input type="number" [(ngModel)]="filters.minPoints" min="0" step="0.1">
</label>
<label>
Min APG
<input type="number" [(ngModel)]="filters.minAssists" (ngModelChange)="onFilterChange()" min="0" step="0.1">
<input type="number" [(ngModel)]="filters.minAssists" min="0" step="0.1">
</label>
<label>
Min RPG
<input type="number" [(ngModel)]="filters.minRebounds" (ngModelChange)="onFilterChange()" min="0" step="0.1">
<input type="number" [(ngModel)]="filters.minRebounds" min="0" step="0.1">
</label>
<label>
Min EFF
<input
type="number"
[(ngModel)]="filters.minEfficiency"
(ngModelChange)="onFilterChange()"
min="0"
step="0.1"
>
+11 -4
View File
@@ -74,20 +74,27 @@ describe('AppComponent', () => {
assert.equal(component.selectedPlayer, null);
});
it('reacts to filter changes without requiring the search button', () => {
it('does not apply changed filters until refresh is requested', () => {
let calls = 0;
let requestedLeague = '';
const api = {
searchPlayers: () => {
searchPlayers: (filters: { league: string }) => {
calls += 1;
requestedLeague = filters.league;
return of({ count: 0, results: [] });
},
} as unknown as PlayerApiService;
const component = new AppComponent(api);
component.onFilterChange();
component.flushPendingSearch();
component.filters.league = 'LBA';
component.filters.league = 'ABA';
assert.equal(calls, 0);
component.search();
assert.equal(calls, 1);
assert.equal(requestedLeague, 'ABA');
});
it('exposes role options and sends the selected role as a filter', () => {
-21
View File
@@ -69,7 +69,6 @@ export class AppComponent {
loading = false;
errorMessage = '';
activeSort: SortKey = 'efficiency_rating';
private pendingSearch: ReturnType<typeof setTimeout> | null = null;
constructor(private readonly playerApi: PlayerApiService) {}
@@ -78,7 +77,6 @@ export class AppComponent {
}
search(): void {
this.cancelPendingSearch();
this.loading = true;
this.errorMessage = '';
@@ -97,19 +95,6 @@ export class AppComponent {
});
}
onFilterChange(): void {
this.cancelPendingSearch();
this.pendingSearch = setTimeout(() => this.search(), 250);
}
flushPendingSearch(): void {
if (!this.pendingSearch) {
return;
}
this.cancelPendingSearch();
this.search();
}
clearFilters(): void {
this.filters = {
q: '',
@@ -182,10 +167,4 @@ export class AppComponent {
return players.find((player) => player.id === this.selectedPlayer?.id) ?? null;
}
private cancelPendingSearch(): void {
if (this.pendingSearch) {
clearTimeout(this.pendingSearch);
this.pendingSearch = null;
}
}
}