Atomic Angular — Doc interne

Saved searches

Name and store a whole search — text, filters, sort, everything the URL carries — behind a starred toggle button, and reopen it later from a paginated list.

A bookmark remembers one document; a saved search remembers a whole search state — the query text, every applied filter, the sort order — as the URL that reproduces it. <saved-search-popover> is the starred toggle that saves or unsaves the current search in one click; <saved-searches> is the paginated list of everything the user has saved.

Concept — a saved search is a URL

SavedSearchesService stores each saved search as its full URL (SearchItem.url), not as a structured filter object. Reopening one means navigating to that URL — navigateToSearch() parses it back into query params — so a saved search stays valid across app versions as long as the URL scheme itself does.

Minimal example

A starred toggle for the current search
search-toolbar.component.ts
import { Component, signal } from "@angular/core";
import { SavedSearchPopover } from "@sinequa/atomic-angular";
import type { SearchItem } from "@sinequa/atomic-angular";

@Component({
  selector: "search-toolbar",
  imports: [SavedSearchPopover],
  template: `
    <saved-search-popover [queryText]="searchInputText()" (onSavedSearch)="onSavedSearch($event)" />
  `,
})
export class SearchToolbarComponent {
  protected readonly searchInputText = signal("quarterly report");

  protected onSavedSearch(search: SearchItem | undefined) {
    // Fires only when *unsaving* — saving happens inside the dialog the popover opens.
    console.log("Unsaved:", search);
  }
}

The popover reads whether the current search is already saved from UserSettingsStore.getSavedSearch(queryText) — there is no separate "saved" input to keep in sync yourself.

How it works

already saved? not saved: opens confirm(name) already saved: unsaves directly reads savedSearches() itemClick(search) SavedSearchPopover UserSettingsStore SavedSearchDialog (SavedSearch.call) SavedSearchesService.saveSearch() SavedSearchesService.deleteSavedSearch() SavedSearchesComponent navigateToSearch() — parses the stored URL

Saving and unsaving are asymmetric on purpose: saving needs a name, so it always goes through SavedSearchDialog; unsaving an already-named search needs no further input, so the popover calls SavedSearchesService.deleteSavedSearch() directly, with no confirmation dialog.

Recipes

The full list, with filter counts and relative dates

Every saved search, as a list
sample.component.ts
import { Component } from "@angular/core";
import { SavedSearchesComponent } from "@sinequa/atomic-angular";

@Component({
  selector: "sample-component",
  imports: [SavedSearchesComponent],
  template: `<saved-searches />`,
})
export class SampleComponent {}

Each row shows a badge with the number of applied filters and a relative date ("2 days ago"), both derived from parsing the stored URL — nothing extra to compute on the caller's side.

Naming and saving explicitly

Calling SavedSearch directly — rather than through the popover — is useful from a custom "save" action that is not a starred toggle.

A plain 'Save this search' button
save-button.component.ts
import { Component, inject, Injector } from "@angular/core";
import { SavedSearch } from "@sinequa/atomic-angular";

@Component({
  selector: "save-button",
  template: `<button (click)="save()">Save this search…</button>`,
})
export class SaveButtonComponent {
  private readonly injector = inject(Injector);

  protected async save() {
    // Resolves once the dialog closes; "dialog-confirm" means the name was saved.
    const result = await SavedSearch.call("quarterly report", { injector: this.injector });
    if (result === "dialog-confirm") console.log("Saved");
  }
}

Keyboard

Same list, same keys as recent searches: ↑ / ↓ to move, Enter to open, Delete to remove (Backspace too on a Mac). While the keyboard focus is in the list, the focused row and the footer say so — a mouse click never shows it.

Options

Prop

Type

Pitfalls

What's next

On this page