BACK
Use casesLocal draft restore — saving a draft locally
Use cases · 15

Local draft restore — saving a draft locally

Pattern

The user filled out half of a long form and accidentally closed the tab. On the next visit the app should bring back their draft. But writing to localStorage on every keystroke is wasteful.

The problem it solves

You need to solve two tasks with one stream: read the saved draft on startup and save new changes at a reasonable rate. Imperatively these tasks scatter across different component methods, and it's easy to forget, for example, that in private mode localStorage throws.

Operators and why they matter

  • defer — reads storage only at subscribe time (not at module import). That matters for SSR.
  • startWith — immediately emits the restored draft as the form's initial value.
  • throttleTime with trailing — caps the write rate but guarantees the last value is still saved.
  • tap — performs the write side effect itself, without changing the data.

Gotchas

  • debounceTime instead of throttle — if the user closes the tab before the pause, the last change isn't saved. Throttle with trailing solves this.
  • auditTime doesn't emit the leading value — the UI would linger on an empty form. Apply it only to the save itself, not to display.
  • localStorage can throw (private mode, quota exceeded) — wrap it in try/catch or turn it into an Observable with catchError.

What you get

The form instantly shows the restored draft, and storage is written rarely and predictably. One stream owns all the draft work.

script.ts // TypeScript
CONSOLE · Console output
Hit Run to see the result...