Atomic Angular — Doc interne

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

One removable chip per applied value
search.page.ts
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

values remain nothing remains QueryParamsStore.filters() filterLeaves — flatten and/or trees one chip per value click x on a chip rebuildWithout(source, chip) updateFilter / addFilter removeFilterByName / removeFilter changed

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.

A second, independent filter list
sample.component.ts
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

Filters supplied and stored by the host
sample.component.ts
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:

reconcile.ts
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

On this page