Session & Flash Data
- Introduction
- Flashing Input
- Flashing Errors
- Reading Old Input
- Automatic Flash in MagicFormData
- Advancing the Flash Bucket
- 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:
Session.flash({
'name': 'John',
'email': '[email protected]',
});
MagicRoute.back();
Flashing Errors
Flash per-field error messages:
Session.flashErrors({
'email': ['The email has already been taken.'],
});
Reading Old Input
In the form view, repopulate via the old() helper:
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:
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.
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():
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.