A composable statechart-driven UI routing system for Fulcro applications.
Provides statechart-based routing with deep busy-checking, cross-chart routing
via :route/reachable, and optional bidirectional URL synchronization.
Uses a well-known session-id constant for the routing statechart session,
keeping the public API simple. Parallel regions handle multiple independent
routing areas within a single chart.
A composable statechart-driven UI routing system for Fulcro applications. Provides statechart-based routing with deep busy-checking, cross-chart routing via `:route/reachable`, and optional bidirectional URL synchronization. Uses a well-known `session-id` constant for the routing statechart session, keeping the public API simple. Parallel regions handle multiple independent routing areas within a single chart.
(?! v & args)Run if the argument is a fn. This function can accept a value or function. If it is a
function then it will apply the remaining arguments to it; otherwise it will just return
v.
Run if the argument is a fn. This function can accept a value or function. If it is a function then it will apply the remaining arguments to it; otherwise it will just return `v`.
(abandon-route-change! app-ish)Sends an event to the statechart that will abandon the attempt to route and close the routing info.
Sends an event to the statechart that will abandon the attempt to route and close the routing info.
(active-leaf-routes app-ish)Returns the set of IDs of the route states that are active and represent the deepest leaf targets,
walking through invocation boundaries into child charts. There can be more than one active leaf
when using parallel nodes. Falls back to the istate itself if its child session doesn't exist yet.
Returns the set of IDs of the route states that are active and represent the deepest leaf targets, walking through invocation boundaries into child charts. There can be more than one active leaf when using parallel nodes. Falls back to the `istate` itself if its child session doesn't exist yet.
(busy? {:fulcro/keys [app] :as env} {:keys [_event] :as data} & args)Returns true if any active route state is busy (dirty form, etc.) at any depth in the invocation tree. Used as the sole guard condition on route transitions.
Returns true if any active route state is busy (dirty form, etc.) at any depth in the invocation tree. Used as the sole guard condition on route transitions.
(clear-override! & _args)Clears the saved failed route event.
Clears the saved failed route event.
(current-invocation-configuration this)Returns the current configuration of the nearest invoked statechart co-located on
this or an ancestor.
Returns the current configuration of the nearest invoked statechart co-located on `this` or an ancestor.
(establish-route-params-node {:keys [id] :route/keys [params]})A custom statechart node that reads route parameters from event data and assigns them
to [:routing/parameters id] in the data model.
A custom statechart node that reads route parameters from event data and assigns them to `[:routing/parameters id]` in the data model.
(force-continue-routing! app-ish)Sends an event to the statechart indicating the most-recently-denied route should be forced.
Sends an event to the statechart indicating the most-recently-denied route should be forced.
(form? Component)Returns true if the given component looks like a Fulcro form using form-state.
Returns true if the given component looks like a Fulcro form using form-state.
(has-routes? {:com.fulcrologic.statecharts/keys [elements-by-id]
:as normalized-statechart}
id)Returns true if the state with the given ID contains routes within normalized-statechart.
NOTE: This inspects a single chart only and does not cross invocation boundaries into child charts.
Returns true if the state with the given ID contains routes within `normalized-statechart`. NOTE: This inspects a single chart only and does not cross invocation boundaries into child charts.
(initialize-route! {:fulcro/keys [app] :as env}
{:com.fulcrologic.statecharts.integration.fulcro.routing/keys
[target]
:as data})Logic that the statechart will run to initialize the target route component's state in the Fulcro database. This is controlled primarily by two options:
sfro/initialize sfro/initial-props
If the target component has a constant ident and initial-state, then neither option is necessary and the default
for sfro/initialize will be :once. If the ident isn't a constant, then you must make sure the the initial-props or initial-state
will lead to data that can be used with (get-ident Class data) to get a valid ident.
Returns the ident of the initialized component.
Logic that the statechart will run to initialize the target route component's state in the Fulcro database. This is controlled primarily by two options: sfro/initialize sfro/initial-props If the target component has a constant ident and initial-state, then neither option is necessary and the default for sfro/initialize will be :once. If the ident isn't a constant, then you must make sure the the initial-props or initial-state will lead to data that can be used with `(get-ident Class data)` to get a valid ident. Returns the ident of the initialized component.
(install-url-sync! app
&
[{:keys [on-route-denied provider url-codec routing/checks]
:or {checks :warn}}])Installs bidirectional URL synchronization for the routing statechart session.
Call AFTER start! completes. Returns a cleanup function that removes all listeners.
The statechart registration key is derived automatically from the routing session's
working memory (::sc/statechart-src).
For state-to-URL sync, url-sync-on-save must be called from the :on-save
handler passed to install-fulcro-statecharts!. Pass app to
url-sync-on-save to enable child chart URL tracking — when a child chart
transitions internally, the URL will update to reflect the full nested state.
Options:
:provider — A URLHistoryProvider. Defaults to (browser-url-history) on CLJS.
Required on CLJ (throws if not provided).:url-codec — A URLCodec instance for encoding/decoding URLs. Defaults to
(ruct/transit-base64-codec). Pass (ruct/transit-base64-codec "/app") to
deploy under a sub-path prefix.:on-route-denied — (fn [url]) called when back/forward navigation is denied by the busy guardInstalls bidirectional URL synchronization for the routing statechart session. Call AFTER `start!` completes. Returns a cleanup function that removes all listeners. The statechart registration key is derived automatically from the routing session's working memory (`::sc/statechart-src`). For state-to-URL sync, `url-sync-on-save` must be called from the `:on-save` handler passed to `install-fulcro-statecharts!`. Pass `app` to `url-sync-on-save` to enable child chart URL tracking — when a child chart transitions internally, the URL will update to reflect the full nested state. Options: * `:provider` — A `URLHistoryProvider`. Defaults to `(browser-url-history)` on CLJS. Required on CLJ (throws if not provided). * `:url-codec` — A `URLCodec` instance for encoding/decoding URLs. Defaults to `(ruct/transit-base64-codec)`. Pass `(ruct/transit-base64-codec "/app")` to deploy under a sub-path prefix. * `:on-route-denied` — `(fn [url])` called when back/forward navigation is denied by the busy guard
(istate {:keys [id child-session-id route/target invoke-params namelist finalize
autoforward on-done exit-target statechart-id]
:route/keys [segment reachable]
:or {invoke-params {}}
:as state-props}
&
children)A state that invokes a statechart on the target component. The target is any registry-compatible
key, and the component must have an sfro/statechart or sfro/statechart-id option.
An istate is just like an rstate in terms of actual routing. See the docstring of rstate for details.
The state :id is always derived from :route/target — passing an explicit :id is an error.
The :fulcro/actors in the statechart's data model will have :actor/component set to the target itself.
Options:
:route/target — The component registry key with a co-located statechart (or statechart-id).:route/segment — (optional) Custom URL path segment string. Defaults to (name target).:route/reachable — A set of route target keywords reachable through the child chart,
or a map of {target-keyword "segment"} when child targets use custom :route/segment values.
When a map is provided, the keys become the reachable set and the values are stored as
:route/reachable-segments for URL restoration.invoke-params — A map merged into the invoke params.namelist, finalize, autoforward — Same as invoke element options.on-done — (fn [env data & rest] ops) run if the child chart hits a final state.exit-target — State ID to transition to on child chart completion.statechart-id — Override the component's co-located chart/id.child-session-id — Explicit session ID for the invoked chart.A state that invokes a statechart on the target component. The `target` is any registry-compatible
key, and the component must have an sfro/statechart or sfro/statechart-id option.
An `istate` is just like an `rstate` in terms of actual routing. See the docstring of `rstate` for details.
The state `:id` is always derived from `:route/target` — passing an explicit `:id` is an error.
The `:fulcro/actors` in the statechart's data model will have :actor/component set to the target itself.
Options:
* `:route/target` — The component registry key with a co-located statechart (or statechart-id).
* `:route/segment` — (optional) Custom URL path segment string. Defaults to `(name target)`.
* `:route/reachable` — A set of route target keywords reachable through the child chart,
or a map of `{target-keyword "segment"}` when child targets use custom `:route/segment` values.
When a map is provided, the keys become the reachable set and the values are stored as
`:route/reachable-segments` for URL restoration.
* `invoke-params` — A map merged into the invoke `params`.
* `namelist`, `finalize`, `autoforward` — Same as `invoke` element options.
* `on-done` — `(fn [env data & rest] ops)` run if the child chart hits a final state.
* `exit-target` — State ID to transition to on child chart completion.
* `statechart-id` — Override the component's co-located chart/id.
* `child-session-id` — Explicit session ID for the invoked chart.(leaf-route? {:com.fulcrologic.statecharts/keys [elements-by-id]
:as normalized-statechart}
id)Returns true if the given state ID IS a leaf route in normalized-statechart (has :route/target and no child routes).
NOTE: This inspects a single chart only and does not cross invocation boundaries. An istate will appear as a leaf
even though it invokes a child chart with deeper routes. Use active-leaf-routes for cross-chart leaf detection.
Returns true if the given state ID IS a leaf route in `normalized-statechart` (has `:route/target` and no child routes). NOTE: This inspects a single chart only and does not cross invocation boundaries. An `istate` will appear as a leaf even though it invokes a child chart with deeper routes. Use `active-leaf-routes` for cross-chart leaf detection.
(override-route! {:com.fulcrologic.statecharts/keys [vwmem event-queue] :as env}
{:com.fulcrologic.statecharts.integration.fulcro.routing/keys
[failed-route-event]}
&
args)(rad-report? Component)Returns true if the given component looks like a RAD report.
Returns true if the given component looks like a RAD report.
(reachable-targets chart)(reachable-targets {:com.fulcrologic.statecharts/keys [elements-by-id]
:as chart}
seen)Returns the set of all route target keywords reachable from the given statechart definition.
Walks all elements finding :route/target values, and recursively includes targets from
:route/reachable sets. Also descends into components that have co-located charts
(sfro/statechart), collecting their targets transitively.
Accepts a normalized chart (from chart/statechart).
Returns the set of all route target keywords reachable from the given statechart definition. Walks all elements finding `:route/target` values, and recursively includes targets from `:route/reachable` sets. Also descends into components that have co-located charts (`sfro/statechart`), collecting their targets transitively. Accepts a normalized chart (from `chart/statechart`).
(record-failed-route! _env {:keys [_event] :as _data} & _args)Stores the failed route event so it can be retried via force-continue-routing!.
Stores the failed route event so it can be retried via force-continue-routing!.
(replace-join! app Parent parent-ident join-key Target target-ident)Logic to update the query of Parent such that join-key is an EQL join to Target.
When parent-ident is nil and Parent declares an ident, the join rewrite is skipped
to avoid writing malformed state (e.g. (assoc-in nil join-key ...)).
Logic to update the query of Parent such that `join-key` is an EQL join to `Target`. When `parent-ident` is nil and Parent declares an ident, the join rewrite is skipped to avoid writing malformed state (e.g. `(assoc-in nil join-key ...)`).
(replace-route-params! app-ish target params)Updates the :route/params for the given currently-active route target and,
if URL sync is installed, replaces the current browser URL using the history
provider's -replace-url! method (no new history entry, no rstate re-entry).
This is the equivalent of the original UISM RAD library's URL replacement signal: components/statecharts can call this when their internal URL-relevant state changes (e.g. report sort/page/selection or control parameter values) so the URL stays bookmarkable without re-running route entry actions.
No-op when URL sync is not installed, which makes it safe to call unconditionally from app code.
Updates the `:route/params` for the given currently-active route `target` and, if URL sync is installed, replaces the current browser URL using the history provider's `-replace-url!` method (no new history entry, no rstate re-entry). This is the equivalent of the original UISM RAD library's URL replacement signal: components/statecharts can call this when their internal URL-relevant state changes (e.g. report sort/page/selection or control parameter values) so the URL stays bookmarkable without re-running route entry actions. No-op when URL sync is not installed, which makes it safe to call unconditionally from app code.
(route-back! app-ish)Navigates back through the installed URL sync provider. Returns true when navigation was attempted, or nil when URL sync is unavailable.
Navigates back through the installed URL sync provider. Returns true when navigation was attempted, or nil when URL sync is unavailable.
(route-current-url app-ish)Returns the current URL from the installed URL sync provider, or nil when unavailable.
Returns the current URL from the installed URL sync provider, or nil when unavailable.
(route-denied? app-ish)Returns true if the routing statechart is currently showing the route-denied info.
Returns true if the routing statechart is currently showing the route-denied info.
(route-forward! app-ish)Navigates forward through the installed URL sync provider. Returns true when navigation was attempted, or nil when URL sync is unavailable.
Navigates forward through the installed URL sync provider. Returns true when navigation was attempted, or nil when URL sync is unavailable.
(route-history-index app-ish)Returns the current history index from the installed URL sync provider, or nil when unavailable.
Returns the current history index from the installed URL sync provider, or nil when unavailable.
(route-sync-from-url! app-ish)Parses the current URL from the installed provider and routes the statechart to match. Returns the routed target keyword, or nil when no provider/session/URL target is available.
Parses the current URL from the installed provider and routes the statechart to match. Returns the routed target keyword, or nil when no provider/session/URL target is available.
(route-to! app-ish target)(route-to! app-ish target data)Attempt to route to the given target.
Attempt to route to the given `target`.
(route-to-event-name target)Given a registry key or component class, returns the event name that can be sent to the routing statechart in order to directly go to that state/route.
Given a registry key or component class, returns the event name that can be sent to the routing statechart in order to directly go to that state/route.
(routes {:routing/keys [root] :keys [id] :as props} & route-states)Emits a state that represents the region containing all of the routes. Generates transitions for direct navigation to any substate that has a routing target.
Also generates cross-chart transitions for targets declared in :route/reachable sets
on istate children. These transitions target the declaring istate and store a
::pending-child-route in the data model so the child chart can self-route on startup.
The :routing/root must be a component with a constant ident (or the app root itself), and a query.
Emits a state that represents the region containing all of the routes. Generates transitions for direct navigation to any substate that has a routing target. Also generates cross-chart transitions for targets declared in `:route/reachable` sets on `istate` children. These transitions target the declaring `istate` and store a `::pending-child-route` in the data model so the child chart can self-route on startup. The :routing/root must be a component with a constant ident (or the app root itself), and a query.
(routing-regions routes)Wraps the routes in a parallel state that includes management of the (optionally modal) route info (information when routing is denied, with the option to override).
Returns a state node :state/route-root containing a parallel node with the routing-info
state and the provided routes.
Wraps the routes in a parallel state that includes management of the (optionally modal) route info (information when routing is denied, with the option to override). Returns a state node `:state/route-root` containing a parallel node with the routing-info state and the provided routes.
(rstate {:keys [id parallel?] :route/keys [target segment params] :as props}
&
children)Create a routing state. Requires a :route/target attribute which should be
anything accepted by comp/registry-key->class.
The state :id is always derived from :route/target — passing an explicit :id
is an error and will throw at chart construction time.
Options:
:route/target — (required) Component class or registry key for this route.:route/segment — (optional) Custom URL path segment string. When absent,
defaults to the simple name of the target (e.g. "UserList").:route/params — (optional) A set of keywords that are route parameters.
When seen as data in a routing event, params are stored in
[:routing/parameters <state-id>] in the data model.:parallel? — (optional) When true, this node is a parallel state.Create a routing state. Requires a `:route/target` attribute which should be anything accepted by `comp/registry-key->class`. The state `:id` is always derived from `:route/target` — passing an explicit `:id` is an error and will throw at chart construction time. Options: * `:route/target` — (required) Component class or registry key for this route. * `:route/segment` — (optional) Custom URL path segment string. When absent, defaults to the simple name of the target (e.g. `"UserList"`). * `:route/params` — (optional) A set of keywords that are route parameters. When seen as data in a routing event, params are stored in `[:routing/parameters <state-id>]` in the data model. * `:parallel?` — (optional) When true, this node is a parallel state.
(send-to-self! this event-name)(send-to-self! this event-name event-data)Send an event to the nearest invoked statechart co-located on this or an ancestor.
Send an event to the nearest invoked statechart co-located on `this` or an ancestor.
The well-known statechart session ID used for the routing statechart.
The well-known statechart session ID used for the routing statechart.
(start! app statechart)(start! app statechart {:keys [routing/checks] :or {checks :warn}})Registers the routing statechart and starts a routing session.
No URL history integration is performed.
Options (optional second map):
:routing/checks — :warn (default) or :strict. Controls whether route
configuration problems are logged as warnings or thrown as errors.Registers the routing `statechart` and starts a routing session. No URL history integration is performed. Options (optional second map): * `:routing/checks` — `:warn` (default) or `:strict`. Controls whether route configuration problems are logged as warnings or thrown as errors.
(ui-current-subroute parent-component-instance factory-fn)Render the current subroute. factory-fn generates a proper element (e.g. comp/factory),
and parent-component-instance is usually this.
WARNING: You MUST put :preserve-dynamic-query? true on the containing component, or hot code reload will wipe the current route.
NOTE: This will NOT properly render a parallel route. You must use ui-parallel-route.
Render the current subroute. `factory-fn` generates a proper element (e.g. comp/factory), and `parent-component-instance` is usually `this`. WARNING: You MUST put `:preserve-dynamic-query? true` on the containing component, or hot code reload will wipe the current route. NOTE: This will NOT properly render a parallel route. You must use `ui-parallel-route`.
(ui-parallel-route parent-component-instance target-registry-key factory-fn)Render ONE of the possible routes underneath a parallel routing node.
parent-component-instance is usually this and factory-fn is usually comp/factory.
NOTE: This will NOT properly render a standard route. You must use ui-current-subroute.
Render ONE of the possible routes underneath a parallel routing node. `parent-component-instance` is usually `this` and `factory-fn` is usually comp/factory. NOTE: This will NOT properly render a standard route. You must use `ui-current-subroute`.
(update-parent-query! {:fulcro/keys [app] :as env} data target-id)Dynamically set the query of the parent of target-id such that its query includes a join to the given target. For
parallel routes the join key will be the registry key of the :route/target of state target-id,
and otherwise it will be :ui/current-route.
Dynamically set the query of the parent of `target-id` such that its query includes a join to the given target. For parallel routes the join key will be the registry key of the :route/target of state `target-id`, and otherwise it will be `:ui/current-route`.
(url-sync-installed? app-ish)Returns true when URL sync has been installed for the routing session.
Returns true when URL sync has been installed for the routing session.
(url-sync-on-save saving-session-id wmem app)An :on-save handler that dispatches to registered URL sync handlers.
Accepts a Fulcro app, enabling child chart URL tracking: when a child session
saves, it walks the parent chain to find the registered root and delegates to
its handler.
The handler receives three arguments: (handler root-sid wmem saving-sid) where
saving-sid is the session that actually saved (may differ from root-sid for
child invocations). This lets the handler distinguish root saves from child saves.
Compose with your own :on-save when calling install-fulcro-statecharts!:
(install-fulcro-statecharts! app
{:on-save (fn [session-id wmem]
(url-sync-on-save session-id wmem app)
(my-other-on-save session-id wmem))})
An `:on-save` handler that dispatches to registered URL sync handlers.
Accepts a Fulcro `app`, enabling child chart URL tracking: when a child session
saves, it walks the parent chain to find the registered root and delegates to
its handler.
The handler receives three arguments: `(handler root-sid wmem saving-sid)` where
`saving-sid` is the session that actually saved (may differ from `root-sid` for
child invocations). This lets the handler distinguish root saves from child saves.
Compose with your own `:on-save` when calling `install-fulcro-statecharts!`:
```
(install-fulcro-statecharts! app
{:on-save (fn [session-id wmem]
(url-sync-on-save session-id wmem app)
(my-other-on-save session-id wmem))})
```(url-sync-provider app-ish)Returns the installed URL history provider for the routing session, or nil when URL sync is not installed.
Returns the installed URL history provider for the routing session, or nil when URL sync is not installed.
(validate-duplicate-leaf-names chart)Checks for route targets whose simple name (used in URL matching) collides. Returns a sequence of issue maps, empty if no duplicates.
Checks for route targets whose simple name (used in URL matching) collides. Returns a sequence of issue maps, empty if no duplicates.
(validate-duplicate-segments {:com.fulcrologic.statecharts/keys [elements-by-id]
:as chart})Checks for leaf route states whose full segment chains collide. Two states with identical segment chains produce ambiguous URL matching. Returns a sequence of issue maps, empty if no duplicates.
Checks for leaf route states whose full segment chains collide. Two states with identical segment chains produce ambiguous URL matching. Returns a sequence of issue maps, empty if no duplicates.
(validate-empty-segments {:com.fulcrologic.statecharts/keys [elements-by-id]})Checks each route state with :route/segment "" against the rules for the
sanctioned 'no URL contribution' marker:
istate).routes node — i.e. walking
:initial from the routes node down through compound states must arrive
at this state.Returns a sequence of issue maps, empty when all empty-segment markers are valid.
Checks each route state with `:route/segment ""` against the rules for the sanctioned 'no URL contribution' marker: * Cannot host a child-chart invocation (i.e. cannot be an `istate`). * Cannot have descendants that are themselves route states. * Must lie on the initial chain of its enclosing `routes` node — i.e. walking `:initial` from the routes node down through compound states must arrive at this state. Returns a sequence of issue maps, empty when all empty-segment markers are valid.
(validate-reachable-collisions chart)Checks for :route/reachable targets that share a simple name with a direct route target.
Returns a sequence of issue maps, empty if no collisions.
Checks for `:route/reachable` targets that share a simple name with a direct route target. Returns a sequence of issue maps, empty if no collisions.
(validate-route-configuration chart mode)Runs all route configuration validators on chart. Reports issues according
to mode (:warn or :strict). Returns the chart unchanged.
Runs all route configuration validators on `chart`. Reports issues according to `mode` (`:warn` or `:strict`). Returns the chart unchanged.
(validate-routing-root chart)Checks that a routes node has a valid :routing/root.
Returns a sequence of issue maps, empty if valid.
Checks that a routes node has a valid `:routing/root`. Returns a sequence of issue maps, empty if valid.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |