Router
Router is JOPS’s hash-based router. It extends View, is declared in a layout as a <Router jops> tag, and is a singleton: one Router per page. Its routes are views; the hash (#home, #detail?id=42) selects the one in front.
import { Router } from "jops-core";Learn more: Routing.
Declaring a Router
Section titled “Declaring a Router”<Router jops animation="slide"> <Home jops path="/home" src="/src/Home.js"></Home> <Detail jops path="/detail" src="/src/Detail.js"></Detail> <View jops path="/about" layout="/src/layout/about.html"></View></Router>Each child tag is a route: a declared view with a path. The tag name is free (<Home>, <view>); jops marks it as a view, src names its class module, layout its layout. The legacy type="jops" and type="jops-event-bind" syntax is still supported.
- The first route is the default. It is shown on startup when the URL has no known route hash, and whenever the hash becomes empty (
href="#", a link to the page itself). - Every route gets
onLayout()at startup; only the route that is shown getsonResume(). - A route’s own layout may declare views, like any other layout.
Attributes
Section titled “Attributes”| Attribute | Values | Description |
|---|---|---|
animation |
"none" (default), "slide", "fade" |
Transition for stacked navigation, see Animation |
screens |
boolean attribute | Gives the Router its own container with full-size screens, see Screens mode |
id, class |
any | In screens mode, copied to the Router’s container |
Navigation paradigms
Section titled “Navigation paradigms”| Pattern | Mechanism | Instance | Android analogy |
|---|---|---|---|
href="#path" |
flat route, hash change | existing route view, reused | tab navigation |
navigate(path, ClassDef?) |
stack | always a new instance | startActivity() |
replace(path, ClassDef?) |
resets the stack | existing route or new instance | startActivity(FLAG_CLEAR_TOP) |
<a href="#detail?id=42">Open</a>Static methods
Section titled “Static methods”Router.singleton()
Section titled “Router.singleton()”Router.singleton(): RouterReturns the page’s Router instance once it has been rendered. Before that (and after the app has ended) there is no instance, so guard calls made outside views:
const router = Router.singleton();if (router?.canGoBack()) router.back();Instance methods
Section titled “Instance methods”navigate()
Section titled “navigate()”navigate(path: string, ClassDef?: typeof View): Promise<void>Creates a new view instance for path, pushes it onto the navigation stack, animates forward and updates the address bar to #path?params.
Parameters
path: the route path with optional query params, for example"/detail?id=42".ClassDef(optional): the view class to create. Required whenpathis not one of the declared routes.
The current view gets onPause(); the new instance gets onLayout() → onResume().
Router.singleton().navigate("/detail?id=42", DetailView);replace()
Section titled “replace()”replace(path: string, ClassDef?: typeof View): Promise<void>Clears the navigation stack and shows path: the existing route view when path is a declared route, otherwise a new instance of ClassDef. Replaces the current history entry and keeps its existing history.state.
Router.singleton().replace("/login");back()
Section titled “back()”back(): voidNavigates back: pops the navigation stack with an animation when it is not empty, otherwise calls history.back(). The view being left gets onBackPressed().
canGoBack()
Section titled “canGoBack()”canGoBack(): booleanReturns true when there is an earlier JOPS history entry to go back to, like checking the back stack in Android.
getParams()
Section titled “getParams()”getParams(): Record<string, string>Returns the current URL query params as a plain object. Works for flat routes (href="#path?k=v") and stacked views (navigate("/path?k=v")). Read them in a route’s onResume() (it runs again when the same route is shown with new params); a stacked view can also read them in onLayout().
onResume() { const { id, mode } = Router.singleton().getParams();}destroy()
Section titled “destroy()”destroy(): voidRemoves the Router’s history listeners, destroys its routes and stacked views and clears the singleton. Called by unmount(); safe to call more than once.
removeSubViews()
Section titled “removeSubViews()”Not supported on a Router: its subviews are its routes. It logs a warning and does nothing.
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
animation |
string |
The value of the tag’s animation attribute ("none" when absent) |
screens |
boolean |
true in screens mode |
Navigation and the lifecycle
Section titled “Navigation and the lifecycle”| Navigation | Outgoing view | Incoming view |
|---|---|---|
Route link (href="#users"), Forward to a route |
onPause() |
onResume() |
| Back to the previous route | onBackPressed(), onPause() |
onResume() |
Same route with new params (#details?id=1 → #details?id=2) |
— | onResume() |
navigate() (stacked view) |
onPause() |
new instance: onLayout() → onResume() |
| Back from a stacked view | onBackPressed(), then destroyed |
onResume() |
| Route link while stacked views are open | stacked views destroyed (no onPause()) |
onResume() |
See View lifecycle for each hook.
Query params
Section titled “Query params”// flat route with params// <a href="#form?tab=profile">Profile</a>
// stacked navigation with paramsRouter.singleton().navigate("/detail?id=42&mode=edit", DetailView);
// read them in the view's onResume()const { id, mode } = Router.singleton().getParams();Values are strings. A route shown again with different params gets onResume() again, so read params there rather than in onLayout().
Animation
Section titled “Animation”| Value | Behaviour |
|---|---|
"none" (default) |
Instant switch |
"slide" |
Forward: the incoming view slides in from the right. Back: the outgoing view slides out to the right |
"fade" |
Crossfade between the outgoing and incoming views |
Animation only runs on navigate() and on back() while the stack is not empty. Switching between flat routes is always instant, and so is a transition involving a view with several top-level elements (except in screens mode). The Router’s container needs position: relative for the animations.
Screens mode
Section titled “Screens mode”<Router jops screens animation="slide" class="content"> <Home jops path="/home" src="/src/Home.js"></Home> <Files jops path="/files" src="/src/Files.js"></Files></Router>With the screens attribute, the Router gets a container of its own and every route and stacked view becomes a full-size screen in it, as in a native app:
- The
<Router>tag is replaced by<div class="jops-router">(plus the tag’s ownidandclass), styledposition: relative; overflow: hidden. Routes are placed inside it, not in the tag’s parent element. - Each route and each view opened with
navigate()orreplace()is wrapped in<div class="jops-screen">, which fills the container (position: absolute; inset: 0), scrolls on its own (overflow: auto) and has an opaque background. - A new view covers the current one, which stays alive underneath. Afterwards the covered screen is
visibility: hiddenandinert, so it keeps its scroll position and is shown unchanged on Back. Inactive flat routes are hidden the same way. slideandfademove only the upper screen, and also work for views with several top-level elements.
.jops-router { flex: 1; min-height: 0; --jops-screen-bg: var(--bg); /* screen background, default Canvas */}.jops-screen { padding: 0 24px 32px;}The properties the Router sets inline (position, inset, overflow and background on screens; position and overflow on the container) take precedence over your stylesheet; set the background with --jops-screen-bg.
Without screens (the default), routes are placed in the tag’s parent element and scroll with the page.