Applied filters
Show what the query is currently filtered by, as one removable chip per value — the counterpart of the filters bar, which shows what a user can filter on.
<applied-filters> shows what the query is filtered by, one chip per value. Contrast with
Filters bar, which shows what a user can filter on.
Concept — one entry, several chips
QueryParamsStore keeps one filter entry per field or per aggregation — three selected authors are a
single values array, and two selected date buckets are a nested or tree. Rendering that directly would
show one chip for three choices, and removing it would drop all three. <applied-filters> expands each entry
into one chip per value first, so each one can be removed independently.
Minimal example
import { Component, inject } from "@angular/core";
import { AppliedFiltersComponent } from "@sinequa/atomic-angular";
import { QueryService } from "@sinequa/atomic-angular";
@Component({
selector: "search-page",
imports: [AppliedFiltersComponent],
template: ` <applied-filters (changed)="search()" /> `,
})
export class SearchPage {
private readonly queryService = inject(QueryService);
protected search() {
this.queryService.search().subscribe();
}
}(changed) fires on any mutation — a removal or a full clear alike — so a host that only needs to re-run its
query can bind that one output and ignore the more precise (removed)/(cleared).
How it works
Removing a chip never deletes the whole stored entry outright: rebuildWithout returns the entry minus
that one value, so the aggregation's other selections survive. A named entry (one carrying the aggregation's
name) is replaced through updateFilter rather than patched, because updateFilter only ever merges —
growing a selection, never shrinking it.
A chip's identity is its leaf filter, not its value: a date distribution's two bounds can share one value
("This year" is modified >= 2026-01-01, "Before this year" is modified < 2026-01-01, differing only by
operator), so tracking by value would make removing one chip drop both.
Recipes
Two backends sharing one screen
Both scopes would otherwise fight over the URL query parameters they have in common.
import { Component } from "@angular/core";
import { AppliedFiltersComponent } from "@sinequa/atomic-angular";
@Component({
selector: "sample-component",
imports: [AppliedFiltersComponent],
template: ` <applied-filters [syncUrl]="false" (changed)="search()" /> `,
})
export class SampleComponent {
protected search() {
// re-run the second backend's own query here
}
}Controlled — the caller owns the state
import { Component, signal } from "@angular/core";
import { AppliedFiltersComponent } from "@sinequa/atomic-angular";
import type { LegacyFilter } from "@sinequa/atomic";
@Component({
selector: "sample-component",
imports: [AppliedFiltersComponent],
template: `
<applied-filters [filters]="applied()" (filtersChange)="applied.set($event)" (changed)="search()" />
`,
})
export class SampleComponent {
protected readonly applied = signal<LegacyFilter[]>([]);
protected search() {
// re-run the query against applied()
}
}Providing [filters] writes nothing to QueryParamsStore: the component only renders what it is given and
emits what the caller should keep on (filtersChange).
Reconciling a facet's own selection after a removal
A facet lit from its own local selection state has to reconcile after a chip is removed elsewhere on the
page — neither the value nor the object reference survives the round-trip (the store rebuilds entries by
spreading them), so compare on filterKey instead:
import { filterKey, filterLeaves } from "@sinequa/atomic-angular";
const inStore = new Set(queryParamsStore.filters().flatMap(filterLeaves).map(filterKey));
selection.update((current) => current.filter((s) => inStore.has(filterKey(s.filter))));Options
Prop
Type
Exports
Prop
Type
Pitfalls
What's next
Aside filters
A collapsible accordion of facets for a sidebar or drawer, with keyboard navigation jumping directly between facet headers.
Data visualization
Render a Sinequa aggregation as a heatmap, a tag or word cloud, or a Chart.js bar/pie/doughnut/timeline — all in controlled mode, like <Aggregation>.