Tutorials
Install a feature at runtime
Start without Reports, install its Module and Mount transactionally, open it, then remove it with an explicit active-entry policy.
Install a feature at runtime
Use this tutorial only when the set of available routes changes while the application runs: plugins, downloaded workspace tools, or tenant-specific modules. Ordinary screen changes use NavigationPort, not Graph updates.
The app starts with Home. Pressing Install reports adds the Reports Module and opens it. Pressing Uninstall removes the Module while Reports is active.
Create Runtime and Session
late final NavigationRuntime runtime = NavigationRuntime(graph: baseGraph());
late final NavigationSession session = runtime.createSession(
id: const NavigationSessionId('dynamic-example'),
);
@override
void dispose() {
runtime.dispose();
super.dispose();
}
Runtime owns the shared Graph revision. Session still owns the window's stack.
Define Reports before installing it
final class ReportsDestination extends NavigationDestination<void> {
const ReportsDestination();
}
NavigationModule reportsModule() => NavigationModule(
id: const NavigationModuleId('reports'),
routes: <NavigationRouteDefinitionBase>[
NavigationRouteDefinition<ReportsDestination, void>(
id: const NavigationRouteId('reports'),
pageBuilder: (context, destination, entry) => const ReportsPage(),
uriCodec: CallbackNavigationUriCodec<ReportsDestination>(
pattern: '/',
encoder: (destination) => Uri(path: '/'),
decoder: (match) => const ReportsDestination(),
),
),
],
);
The Module is a normal immutable definition. It becomes reachable only after mounting.
Install Module and Mount together
final results = await runtime.updateGraph(
(builder) {
final module = reportsModule();
builder.installModule(module);
builder.mount(NavigationMount(
id: const NavigationMountId('reports-root'),
moduleId: module.id,
scopeId: const NavigationScopeId('root'),
pathPrefix: '/reports',
));
},
activeEntries: const RejectActiveNavigationEntries(),
);
if (results[session.id]?.isCommitted ?? false) {
session.controller.push<void>(const ReportsDestination());
}
The candidate Graph is validated before any Session adopts it. Inspect the result for every Session before treating installation as successful.
Choose uninstall behavior
Reject removal while Reports is open:
activeEntries: const RejectActiveNavigationEntries()
Or remove active Reports entries:
await runtime.updateGraph(
(builder) => builder.uninstallModule(const NavigationModuleId('reports')),
activeEntries: const RemoveActiveNavigationEntries(),
);
Use MigrateActiveNavigationEntries when an active route must become another compatible Destination while preserving ticket result types.