Class: CoreRouter

Oracle® JavaScript Extension Toolkit (JET)
9.0.0

F24343-01

Signature:

class CoreRouter< D extends {[key: string]: any} = {[key: string]: any}, P extends {[key: string]: any} = {[key: string]: any}, ParentD extends {[key: string]: any} = {[key: string]: any}, ParentP extends {[key: string]: any} = {[key: string]: any}>

QuickNav

Fields

CoreRouter

Version:
  • 9.0.0
Since:
  • 8.0.0
Module:
  • ojcorerouter

Module usage

See JET Module Loading for an overview of module usage within JET.

Typescript Import Format
//This class is exported directly as module. To import it
import CoreRouter= require("ojs/ojcorerouter");

Generic Parameters
ParameterDescription
DDetail object for the router state
PParameters object for the router state
ParentDDetail object for the parent router state
ParentPParameters object for the parent router state

JET In Typescript

A detailed description of working with JET elements and classes in your typescript project can be found at: JET Typescript Usage.

Description

The router manages application navigation by tracking state through the browser URL. The router's core responsibility is to publish state changes due to navigation so that listeners can react and perform their own logic, such as loading modules.

The root router instance is the top-most router, and it has no parent. This instance may be created only once per application, and attempting to create more than one root instance will result in an error.

Create a CoreRouter with a named route and a redirect rule pointing to that route.
The route with the redirect has a blank path value, making it the default route. However, since it redirects to path1, that is the effective default route.

var root = new CoreRouter([
  { path: 'path1' },
  { path: '', redirect: 'path1' }
]);

With RegExp as path.
Note that all paths matching the regular expression will be using this configuration entry.

var root = new CoreRouter([
  { path: /path-?/ },
  { path: '', redirect: 'path-1' }
])

With multiple path matches in descending order.
When using RegExp paths, the order of the routes defined is significant. When searching for a matching state, the router will always search top-down to find the first matching state.

In the example below, the value "path-1" will match the first route and will be the one used, even though it would've also matched the second route.


var root = new CoreRouter([
  { path: /path-[0-9]/ },
  { path: /path-?/ },
  { path: new RegExp('.*') }
])

A child router
Child router are created with the CoreRouter.createChildRouter method. All arguments to that function are the same as what would be passed to the constructor for CoreRouter.

var child = root.createChildRouter(
  [    // routes
    { path: 'dashboard' }
  ]
);

A child router which doesn't manipulate history
Some routing use cases want to use the Observables of the router without manipulating the browser history, such as navigating through a wizard whose individual steps shouldn't be bookmarked. Here a child router is created and configured to not manipulate history.

var child = root.createChildRouter(
  [
    { path: 'dashboard' }
  ],
  {
    history: 'skip'
  }
)

Constructor

new CoreRouter(routes, options, parentRouter)

Parameters:
Name Type Argument Description
routes Array.<CoreRouter.DetailedRouteConfig<D> | CoreRouter.RedirectedRouteConfig> An array of routes that this router will recognize
options CoreRouter.CreateOptions.<P> <optional>
The configuration options for this router.
parentRouter CoreRouter.<ParentD, ParentP> <optional>
A parent router, if creating a child router, or null/undefined if this is the root router.

Fields

beforeStateChange :CoreRouter.Observable.<CoreRouter.VetoableState.<D, P>>

An observable which publishes state changes that are about to be set as the current state for the router. Subscribers can choose to listen to these publishes to guard against the router navigating out of the current state.

The published value given to the subscriber is a CoreRouter.ResultableData, and it can be used to prevent navigation out of the current state.


router.beforeStateChange.subscribe(function (args) {
  var state = args.state;
  var accept = args.accept;
  // If we don't want to leave, block navigation
  if (currentViewmodel.isDirty) {
    accept(Promise.reject('model is dirty'));
  }
});

The value returned can be a boolean or Promise.

currentState :CoreRouter.Observable.<CoreRouter.ActionableState.<D, P>>

An observable which publishes the change to the current router state. Subscribers can listen to these publishes to react to the state change and perform other work, such as loading modules.

The published value given to the subscriber is a CoreRouter.ResultableData, and it can be used to report back to the router any issues or asynchronous activity that must be completed before the transition is finalized.


router.currentState.subscribe(function (args) {
  var state = args.state;
  var name = state.path;
  var complete = args.complete;
  // Load the module and return Promise to CoreRouter
  complete(
    Promise.all([
      ModuleUtils.createView({ viewPath: 'views/' + name + '.html' }),
      ModuleUtils.createViewModel({ viewModelPath: 'viewModels/' + name })
    ])
  );
});

Subscribers listening to the change to perform asynchronous work, such as loading modules, can return the Promises from those operations through the complete callback. Any errors or Promise rejections returned will cause the transition to fail, and the error will be propagated by the CoreRouter.errors observable. The returned value must be a Promise.

Methods

createChildRouter<ChildD extends {[key: string]: any} = {[key: string]: any}, ChildP extends {[key: string]: any} = {[key: string]: any}>(routes, options) : {CoreRouter.<ChildD, ChildP>}

Create a child router from the current router. The child will be associated with the parent router's state, therefore, the parent must be in a current state (by calling CoreRouter.go or CoreRouter.sync). Calling this method from a parent without a current state, or calling the method twice for the same state will result in an error.

Only one child router will be active per parent router, and only in the parent router's current state. When the parent router changes states, and the previous state had a child router, it will be disposed of. This means that child routers should always be recreated each time the state is activated. This is typically done in the viewmodel's constructor/initialize functions.


this.initialize = function (args) {
  this.childRouter = args.parentRouter.createChildRouter([
    { path: 'child-path' }
  ]);
}.bind(this);

Parameters:
Name Type Argument Description
routes Array.<CoreRouter.DetailedRouteConfig<ChildD> | CoreRouter.RedirectedRouteConfig> The routes to configure for the child router.
options CoreRouter.CreateOptions.<ChildP> <optional>
Options to pass to the creation of the router. Currently, the support options are:
  • history: "skip"
Note that if the current router doesn't update history (history='skip'), then no descendant routers will update history either, regardless of whether the flag is specified.
See:
  • CoreRouter.createRouter
Returns:
The child router instance for the current state
Type
CoreRouter.<ChildD, ChildP>

destroy()

Destroys the router instance and removes the browser navigation listener (Back/Forward). Note that this function only applies to the root router instance; calling it on child routers will have no effect.

go(route) : {Promise<CoreRouter.CoreRouterState<D, P>>}

Navigate the router to a new path. Each argument to this function should be of type CoreRouter.Route.

Navigate to a page
Navigate to a page simply by supplying the path matching the route as an array of strings. This method, like CoreRouter.sync returns a Promise to indicate if the transition was successful. You can chain the Promise to do post-processing if you choose.

router.go({path: 'dashboard'})
.then(function () {
  this.navigated = true;
})
// URL "/dashboard"

Navigate passing dynamic state parameters
Paths are any string within the array to go(), and parameters are any objects in the array. Parameters are always associated with the previous path segment (in this case, "dashboard"), and must have scalar values.
These parameters are made available via the CoreRouterState.params object.

router.go({path: 'dashboard', params: {name: 'Dashboard'}})
// URL "/dashboard;name=Dashboard"

Navigate to a nested path
Nested paths are simply another string in the array passed to go(). When an entry in the array is a complex object, it's associated with the previous path entry.
In this example, formatted for clarity, "employee" is the path which will receive the parameters object containing "id" value.

router.go(
  {path: 'employee', params: {id: 456}},
  {path: 'contacts'}
])
// URL "/employee;id=456/contacts"

Catching navigation errors
Errors encountered during navigation are returned as Promise rejections, and can be caught with the catch() method.
The types of errors that can occur are:
  • No matching state
  • State change veto'd
  • Downstream state change listener errors

router.go({path: 'home'})
.catch(function (error) {
  console.error('Routing problem "' + error + '"');
});

Parameters:
Name Type Description
route CoreRouter.Route<P>[] The route(s) to navigate. Pass multiple routes as separate arguments.
Returns:
A Promise which will resolve with the state to which the router transitioned, if successful. If the transition fails, the Promise will be rejected.
Type
Promise<CoreRouter.CoreRouterState<D, P>>

sync() : {Promise<CoreRouter.CoreRouterState<D, P>>}

Synchronize the router with the current URL. This method tells the router that it should set its internal state to match the values in the URL. Each router at each level sychronizes only the parts of the URL in which it's interested.

The top-most root router's "base" is defined by the baseUrl option passed to UrlPathAdapter, if it's used. If using UrlParamAdapter, the base is document.location.pathname.

sync() is normally called immediately after the router is created so that the default state can be made current. Much like CoreRouter.go, sync() returns a Promise indicating if the synchronization was successful. A failure could mean that the router doesn't have a default state (see examples in CoreRouter) or the state being synchronized is invalid for the current router.

Synchronize the default state of a root router. This assumes that the baseUrl is "/" and the user is visiting the root of the application.


var root = new CoreRouter([
  { path: '', redirect: 'home' },
  { path: 'home' }
]);
root.sync()
.catch(function (error) {
  console.error('CoreRouter.sync failed "' + error + '"');
})

Synchronize a child router. This assumes that the parent's current state is browse and the user is visiting browse/department.


var child = new CoreRouter(
  [
    { path: 'department' }
  ],
  null,
  parentRouter
);
child.sync()
.then(function (success) {
  if (success) {
    console.log('Child router synchronized');
  }
})
.catch(function (error) {
  console.error('Child router.sync error "' + error + '"');
})

Returns:
A Promise which, when resolved, indicates that the sync was successful. A Promise rejection indicates that the sync failed. An error message may be returned describing the reason for the rejection.
Type
Promise<CoreRouter.CoreRouterState<D, P>>

Type Definitions

ActionableState<D = {[key: string]: any}, P = {[key: string]: any}>

A wrapper object which contains a state and a complete callback that can be used by the subscriber to return a Promise for its asynchronous operations.
Properties:
Name Type Description
state CoreRouterState.<D, P> The CoreRouterState object
complete function(Promise<any>): null The callback function the subscriber can use to return a Promise for its asynchronous activities. Invoking this callback is optional, but allows for the subscriber to delay the completion of the router state transition until its own asynchronous activities are done.

CreateOptions<P = {[key: string]: any}>

An object describing configuration options during the creation of a root CoreRouter instance.
Properties:
Name Type Argument Description
history 'skip' <optional>
Indicate if history tracking should be skipped. By default, the router will add a new history entry each time CoreRouter.go is called. Setting this option to 'skip' will disable that.
urlAdapter CoreRouter.UrlAdapter<P> <optional>
The adapter which handles reading and writing router states from/to the browser URL. If not specified, this will default to UrlPathAdapter.

DetailedRouteConfig<D = {[key: string]: any}>

A route config object configures a path and associated information to which a router can navigate, and is used to build the CoreRouter.CoreRouterState during transitions. This route config type can specify a detail object which can be referenced in the state.
Properties:
Name Type Argument Description
path string | RegExp The path of the route. This may be an exact- match string, or a regular expression.
detail D <optional>
An optional detail object which is passed to the route when it is navigated to.

Observable

An Observable which can receive subscriptions for new Observers
Properties:
Name Type Description
subscribe function(function(T): void): CoreRouter.Observer Subscribe to the observable to get notifications when the value changse. The subscriber callback will receive the value as its single argument. Calling subscribe will return the subscriber object, which can be used to unsubscribe from the observable.

Observer

An Observer is the result of subscribing to an Observable, and can be used to unsubscribe.
Properties:
Name Type Description
unsubscribe function(): void Unsubscribe the observable from further modifications to the value.

RedirectedRouteConfig

A RouteConfig object configures a path and associated information to which a router can navigate, and is used to build the CoreRouter.CoreRouterState during transitions. This route config type can specify a redirect to another route.
Properties:
Name Type Argument Description
path string | RegExp The path of the route. This may be an exact- match string, or a regular expression.
redirect string <optional>
An optional name of a route to which paths matching this route will redirect. The redirected route's path must be of type string.

UrlAdapter<P = {[key: string]: any}>

A URL adapter manages reading/writing router states from/to the browser URL.
Properties:
Name Type Description
getUrlForRoutes ((routes: CoreRouter.Route<P>[]) => string) Get the full URL for the given routes.
getRoutesForUrl (() => CoreRouter.Route<P>[]) Given the current browser URL, get all of the routes, starting from the root, down to the last child.

VetoableState<D = {[key: string]: any}, P = {[key: string]: any}>

A wrapper object which contains a state and an accept callback that can be used by the subscriber to return a Promise for its acceptance or rejection of the state transition.
Properties:
Name Type Description
state CoreRouterState.<D, P> The CoreRouterState object
accept function(Promise<any>): null The callback function the subscriber can use to return a Promise indicating whether the state transition ought to be accepted (true) or rejected (false). A Promise rejection will veto the state transition; any Promise resolution (or not invoking the callback at all) will accept the transition.