# Session & Flash Data The `Session` facade provides flash data that survives exactly one navigation hop, letting you pass form input and validation errors across a back-navigation without temporary controller state. - [Introduction](#introduction) - [Flashing Input](#flashing-input) - [Flashing Errors](#flashing-errors) - [Reading Old Input](#reading-old-input) - [Automatic Flash in MagicFormData](#automatic-flash-in-magicformdata) - [Advancing the Flash Bucket](#advancing-the-flash-bucket) - [Testing](#testing) ## Introduction The `Session` facade provides Laravel-style flash data that survives exactly one navigation hop. Use it to repopulate a form after a failed submit and a back navigation without wiring temporary state through controllers, the router, or global singletons. The store has two buckets: the **current** bucket (readable by the view being built right now) and the **next** bucket (being collected by the currently-active handler). A call to `Session.tick()` promotes `next` into `current`, so flashed data is visible on exactly one frame. ## Flashing Input Flash a map of values before navigating away: ```dart Session.flash({ 'name': 'John', 'email': 'john@test.com', }); MagicRoute.back(); ``` ## Flashing Errors Flash per-field error messages: ```dart Session.flashErrors({ 'email': ['The email has already been taken.'], }); ``` ## Reading Old Input In the form view, repopulate via the `old()` helper: ```dart WFormInput( initialValue: old('email') ?? '', ); if (Session.hasError('email')) WText(Session.error('email')!, className: 'text-red-500'); ``` `Session.oldRaw(field)` returns the original typed value (booleans, numbers, custom objects) instead of stringifying it. ## Automatic Flash in MagicFormData `MagicFormData.validate()` automatically flashes the current form data when validation fails, so you never need to wire it manually: ```dart void _submit() { if (!form.validate()) return; // form data is auto-flashed on failure controller.register(form.data); } ``` After a back navigation and a `Session.tick()`, `old('email')` returns the last-submitted value. ## Advancing the Flash Bucket Flash data survives exactly one navigation. Advance the bucket only when the router location actually changes. Do **not** wire `Session.tick` directly to the router delegate listener: the delegate can notify for more than real navigation (redirect re-evaluation, notifier rebuilds) and would expire flash data prematurely. ```dart var lastLocation = MagicRouter.instance.currentLocation; MagicRouter.instance.routerConfig.routerDelegate.addListener(() { final currentLocation = MagicRouter.instance.currentLocation; if (currentLocation == lastLocation) return; lastLocation = currentLocation; Session.tick(); }); ``` Place this in a `ServiceProvider.boot()` after `Magic.init()` completes. ## Testing In tests, always reset the store in `setUp()`: ```dart setUp(() { MagicApp.reset(); Magic.flush(); Session.reset(); }); ``` Swap the backing store with a custom `SessionStore` via `Session.setStore(store)` if you need isolated buckets per test group.