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
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
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
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.
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
Bookmarks
A starred toggle button on any document, and a paginated list of the user's bookmarks — reopening one re-runs the query it came from to land back on the exact record.
Recent searches
An automatically populated, paginated list of the user's past searches — the same shape as saved searches, with nothing to save explicitly.