Skip to main content
Cindel watchers are Dart Streams that emit after committed database changes. Instead of manually reloading screens after every write, you subscribe to a watcher and let Cindel push fresh data whenever something relevant changes. Local writes notify watchers directly; external changes are caught through periodic polling (default 50 ms).

Watcher Types

Choose the watcher that fits how your UI consumes data: Lazy variants emit a void signal rather than the data itself — use them when you manage your own cache and only need to know that something changed.

Common Options

Every watcher accepts two common options:
  • pollInterval — how often polling checks for changes that were not delivered directly. Defaults to Duration(milliseconds: 50).
  • fireImmediately — when true, the stream emits the current value as soon as you subscribe, before any writes occur.

Object Watcher

Use watchObject to track one typed object by id on a detail or edit screen. The emitted value is T? — it is null when the object has been deleted or was never written.

Collection Watcher

Use watchCollection to observe the entire typed collection. This is convenient for small collections or screens that intentionally show every record.
For large collections, prefer a query watcher with filtering, sorting, and limits so the stream only delivers the slice of data your UI actually renders.

Query Watcher

Use query.watch() to observe a typed query result. Query watchers are the best default for list screens because you can push filtering, sorting, and pagination into the database rather than into widget code.

Lazy Watchers

Lazy variants (watchObjectLazy, watchCollectionLazy, watchLazy) emit void instead of data. Use them when your app has its own state management layer and you only need an invalidation signal to know when to reload.

Change-Set Watcher

db.watchCollectionChanges(collectionName) emits a lower-level CindelChangeSet for every committed write to that collection. Use it for advanced cache invalidation, diagnostics, or tooling layers that need to know exactly which document ids changed.
CindelChangeSet exposes these fields: Most apps should use typed watchers. Reach for change-set watchers only when you need fine-grained control over a custom cache or diagnostic tool.

Watcher Lifecycle

Always cancel watcher subscriptions when the owning widget or state object is disposed. A watcher subscription that outlives its widget continues to process database events and can silently update stale state or cause memory leaks.Match the watcher’s lifetime to the UI state it drives — a screen-level watcher should be cancelled in dispose, and a short-lived component watcher should be cancelled when that component is removed.
The standard pattern is to store the StreamSubscription and cancel it on disposal:

Usage Guidance

  • Query watchers — best default for list screens. Push filtering, sorting, and limits into the query so the stream delivers only what the screen needs.
  • Object watchers — best for detail and edit screens that track one record. Handle the nullable emission to detect deletion.
  • Lazy watchers — best when you manage your own cache. The signal is cheap; you decide whether and when to reload.
  • Collection watchers — convenient for small, bounded collections such as settings or categories.
  • Change-set watchers — for custom cache layers, diagnostics, and advanced tooling only.
Keep watcher callbacks small. Derive state from the emitted data and avoid long-running work inside a listen callback. If a listener triggers asynchronous work, ensure the owning state object can safely ignore stale results after it is disposed.
On Web (SQLite/OPFS), watcher delivery is single-tab only. Writes in one browser tab are not automatically broadcast to watchers in another tab.