Class: Router

Oracle® JavaScript Extension Toolkit (JET)
1.2.0

E65435-01

QuickNav

Fields

oj. Router

Version:
  • 1.2.0
Since:
  • 1.1.0

JET Router

The router is designed to simplify writing navigation for Single Page Applications. The approach taken is to think of navigation in terms of states and transitions instead of URLs and hashes. A router is always in one in a number of possible states and when a UI action is taken in the application, a transition between states is executed. The router is responsible to properly format the URL to reflect the current state and to restore the application to the matching state when the URL changes.

Building navigation is done in three steps:

Define the states that can be taken by the router:

var router = oj.Router.rootInstance;
// Add three states to the router with id 'home', 'book' and 'tables
router.configure({
   'home':   { label: 'Home',   value: 'homeContent', isDefault: true },
   'book':   { label: 'Book',   value: 'bookContent' },
   'tables': { label: 'Tables', value: 'tablesContent' }
});

var viewModel = {
   router: router
};

oj.Router.sync().then(
   function() {
      ko.applyBindings(viewModel);
      $('#globalBody').show();
   },
   function(error) {
      oj.Logger.error('Error when starting router: ' + error.message);
   });
Trigger a state transition when user ask to navigate:

<div id="routing-container">
   <div id='buttons-container' data-bind="foreach: router.states">
     <!-- Use the go function of the state as the handler for a click binding -->
     <input type="button"
            data-bind="click: go,  attr: {id: id},
            ojComponent: {component: 'ojButton', label: label}"/>
   </div>
</div>
Listen to the state change and updates the dependent parts:

<!-- Display the content of the current state -->
<h2 id="pageContent" data-bind="text: router.currentValue"/>

Constructor

new Router()

A Router cannot be instantiated. A static Router is created when the module is loaded and can be accessed using the method rootInstance. A child router can be created using the method createChildRouter.
Source:
See:

Requires

  • module:ojs/ojcore
  • module:knockout

Classes

urlParamAdapter
urlPathAdapter

Fields

<static> defaults

A set of Router defaults properties.
Warning:
Defaults can not be changed after the first call to sync() has been made. To re-initialize the router, you need to call dispose() on the rootInstance first then change the defaults.
Properties:
Name Type Description
urlAdapter Object an instance of the url adapter to use. Possible values are an instance of oj.Router.urlPathAdapter or oj.Router.urlParamAdapter.
baseUrl string the base URL to be used for relative URL addresses. If not defined, it is the current URL without the document. For example http://www.example.com/myApp. This is needed by the Router to properly parse the URL.
Source:
Examples

Change the default URL adapter to the urlParamAdapter

oj.Router.defaults['urlAdapter'] = new oj.Router.urlParamAdapter();

Change the base URL

oj.Router.defaults['baseUrl'] = 'http://www.example.com/myApp';

<static, readonly> rootInstance :oj.Router

The static instance of oj.Router representing the unique root router. This instance is created at the time the module is loaded.
All other routers will be children of this object. The name property of this router is 'root'. The parent property is null.
Source:
Example

Retrieve the root router and configure it:

var router = oj.Router.rootInstance;
router.configure({
   'home':   { label: 'Home',   value: 'homeContent', isDefault: true },
   'book':   { label: 'Book',   value: 'bookContent' },
   'tables': { label: 'Tables', value: 'tablesContent' }
});

<static, readonly> transitionedToState

A signal dispatched when the state transition has completed either by successfully changing the state or cancelling.
The parameter of the event handler is a boolean true when the state has changed.
This is usefull when some post processing is needed or to test the result after a state change.
Source:
Example

Creates promise that resolve when the state transition is complete.

var promise = new Promise(function(resolve, reject) {
      oj.Router.transitionedToState.add(function(result) {
         if (result.hasChanged) {
            oj.Logger.info('The state has changed');
         }
         resolve();
      });

<readonly> currentState :function():(oj.RouterState|undefined)

A Knockout observable that returns the current RouterState if it is defined.
Source:
Example

Hide a panel when the state of the router is not yet defined:

   <div data-bind="if: router.currentState()">
      <!-- content of the panel -->
   </div>

<readonly> currentValue :function()

A Knockout observable that returns the value property of the current state.
The state value property is the part of the state object that will be used in the application. It is a shortcut for router.currentState().value;
Source:
Example

Display the content of the current state:

<h2 id="pageContent" data-bind="text: router.currentValue"/>

defaultStateId :string|undefined

The state id of the default state for this router. The value is set when configure is called on the router and the state isDefault property is true. If it is undefined, the router will start without a state selected. This property is writable and can be used to set the default state id when the router is configured using a callback.
Source:

<readonly> moduleConfig

An object to simplify integration between ojRouter and ojModule. Use this object to configure an ojModule where the module name is the router state. When the router changes state, ojModule will automatically load and render the content of the module name specified in the value of the current RouterState object.
The object moduleConfig provide the following functionality to the ojModule binding:
  1. the name of ojModule binding will be the value property of the current state of the router. If value is not defined or if it is not a string, the id property will be used
  2. The router object is passed as a parameter to the viewModel of the module
  3. The callback canExit will be invoked on the viewModel. If canExit is not defined on the viewModel, it will be invoked on the RouterState
Source:
Examples

Configure an ojModule binding with a router

<!-- This is where your main page content will be loaded -->
<div id="mainContainer" data-bind="ojModule: router.moduleConfig"></div>

Creates a child router in the viewModel of a module

var viewModel = {
   initialize: function(params) {
      // Retrieve the parent router from the parameters
      var parentRouter = params.valueAccessor().params;
      // Create a child router for this viewModel
      this.router = parentRouter.createChildRouter('chapter')
         .configure({
            'preface':  { label: 'Preface',   value: storage['preface']  },
            'chapter1': { label: 'Chapter 1', value: storage['chapter1'] },
            'chapter2': { label: 'Chapter 2', value: storage['chapter2'] },
            'chapter3': { label: 'Chapter 3', value: storage['chapter3'] }
         });
      oj.Router.sync();
   },

   // canExit callback will be called here
   canExit: function() {
      return (okToExit) ? true: false;
   }
};

<readonly> name :string

A string identifier of the router. It is required the name is unique within all the sibling routers.
Source:
See:

<readonly> parent :oj.Router|undefined

The parent router if it exits. Only the 'root' router does not have a parent router.
Source:

<readonly> stateId :function(string=): string

A Knockout observable that returns the id of the current state of the router.
Source:

<readonly> states :Array.<oj.RouterState>|null

An array of all the possible states of the router. This array is null if the router is configured using a callback.
Source:
See:

Methods

<static> sync() → {Promise.<{hasChanged: boolean}>}

Synchronise the router with the current URL. The process parse the URL and
  1. transition the router to a new state matching the URL.
  2. initialize the bookmarkable storage.
  3. dispatch a transitionedToState signal.
It has to be called after a router is configured, to synchronise the URL with the router state.
If a default state is defined, the router will transition to it, otherwise no transition will occur and the router will be in an undefined state.
Because the process of transitioning between two states invokes callbacks (canExit, canEnter) that are promises, this function also returns a promise.
Source:
Returns:
A Promise that resolves when the router is done with the state transition.
When the Promise is fullfilled, the parameter value is an object with the property hasChanged.
The value of hasChanged is:
  • true: If the router state changed.
When the Promise is rejected, the parameter value is:
  • An Error object stipulating the reason for the rejection when an error occurred during the resolution.
Type
Promise.<{hasChanged: boolean}>
Examples

Start the root instance

var router = oj.Router.rootInstance;
// Add three states to the router with id 'home', 'book' and 'tables
router.configure({
   'home':   { label: 'Home',   value: 'homeContent', isDefault: true },
   'book':   { label: 'Book',   value: 'bookContent' },
   'tables': { label: 'Tables', value: 'tablesContent' }
});

var viewModel = {
   router: router
};

oj.Router.sync().then(
   function() {
      ko.applyBindings(viewModel);
      $('#globalBody').show();
   },
   function(error) {
      oj.Logger.error('Error when starting the router: ' + error.message);
   }
);

Synchronise a newly created child Router and retrieve the bookmarkable state

 oj.Router.sync().then(
    function() {
       var color = viewModel.router.retrieve();
       if (color) {
          $('#chapter').css('background', color);
       }
    },
    function(error) {
       oj.Logger.error('Error during sync: ' + error.message);
    }
 );

configure(option) → {oj.Router}

Configure the states of the router. The router can be configured in two ways:
  • By describing all of the possible states that can be taken by this router.
  • By providing a callback returning a RouterState object given a string state id.
This operation reset any previous configuration.
This operation is chainable.
Parameters:
Name Type Description
option Object.<string, {label: string, value, isDefault: boolean}> | function(string): (oj.RouterState | undefined) Either a callback or a dictionary of states.
A callback:

stateFromIdCallback (stateId) → {oj.RouterState|undefined}

A function returning a RouterState given a string state id.
When using a callback, the states property will always be null since states are defined on the fly.
See second example below.
A dictionary of states:
It is a dictionary in which the keys are state ids and values are objects defining the state.
See first example below.
Key
Type Description
string the state id. See the RouterState id property.
Properties
Name Type Argument Description
label string <optional>
the string for the link. See the oj.RouterState#label property.
value * <optional>
the object associated with this state. See the oj.RouterState#value property.
isDefault boolean <optional>
true if this state is the default. See the Router defaultStateId property.
canEnter function(): boolean) | (function(): Promise <optional>
A callback that either returns a boolean or the Promise of a boolean. If the boolean is true the transition will continue. The default value is a method that always returns true. See the oj.RouterState#canEnter property.
enter function() <optional>
The callback executed when entering this state. See the oj.RouterState#enter property.
canExit function(): boolean) | (function(): Promise <optional>
A callback that either returns a boolean or the Promise of a boolean. If the boolean is true the transition will continue. The default value is a method that always returns true. See the oj.RouterState#canExit property.
exit function() <optional>
The callback executed when exiting this state. See the oj.RouterState#exit property.
Source:
See:
Returns:
the oj.Router object this method was called on.
Type
oj.Router
Examples

Add three states with id 'home', 'book' and 'tables':

router.configure({
   'home':   { label: 'Home',   value: 'homeContent', isDefault: true },
   'book':   { label: 'Book',   value: 'bookContent' },
   'tables': { label: 'Tables', value: 'tablesContent' }
});

Define a function to retrieve the state:

router.configure(function(stateId) {
   var state;

   if (stateId) {
      var data = getStates(); // Return a array of RouterState keyed by stateId
      if (data) {
         state = data[stateId];
      }
   }
   return state;
});

createChildRouter(name) → {oj.Router}

Create a child router with the given name.
Parameters:
Name Type Description
name string The unique name representing the router.
Source:
Throws:
An error if a child router exist with the same name.
Returns:
the child router
Type
oj.Router
Example

Create a child router of the root:

router = oj.Router.rootInstance;
childRouter = router.createChildRouter('chapter');

dispose()

Dispose the router.
Erase all states of this router and its children. Remove itself from parent router child list.
When this method is invoked on the rootInstance, it also remove internal event listeners and re-initialize the defaults.
Source:

getState(stateId) → {oj.RouterState|undefined}

Return the oj.RouterState object which state id matches one of the possible states of the router.
Parameters:
Name Type Description
stateId string the id of the requested oj.RouterState object.
Source:
Returns:
the state object matching the id.
Type
oj.RouterState | undefined
Example

Retrieve the RouterState for id 'home':

var homeState = router.getState('home');
var homeStateValue = homeState.value;

go(stateId) → {Promise}

Go is used to transition to a new state using a state id. If the state id is undefined, go to the default state of the router.
A transitionedToState signal is dispatched when the state transition has completed.
Parameters:
Name Type Argument Description
stateId string <optional>
The id of the state to transition to.
Source:
Returns:
A Promise that resolves when the router is done with the state transition.
When the promise is fullfilled, the parameter value is an object with the property hasChanged.
The value of hasChanged is:
  • true: If the router state changed.
When the Promise is rejected, the parameter value is:
  • An Error object stipulating the reason for the rejection when an error occurred during the resolution.
Type
Promise
Examples

Transition a router to the state id 'home':

router.go('home');

Transition a router to its default state and handle errors:

router.go().then(
   function(result) {
      if (result.hasChanged) {
         oj.Logger.info('Router transitioned to default state.');
      }
      else {
         oj.Logger.info('No transition, Router was already in default state.');
      }
   },
   function(error) {
      oj.Logger.error('Transition to default state failed: ' + error.message);
   }
);

retrieve() → {*}

Retrieve the additional data stored in the URL.
Source:
Returns:
the content stored in the URL
Type
*
Example

Retrieve the value of the background color stored in the URL:

 oj.Router.sync().then(
    function() {
       var color = viewModel.router.retrieve();
       if (color) {
          $('#chapter').css('background', color);
       }
    },
    function(error) {
       oj.Logger.error('Error during sync: ' + error.message);
    }
 );

store(data)

Store additional data for this router that will be added in a compressed form to the URL so it can be bookmarked. When calling this method, the URL is immediately modified.
Parameters:
Name Type Description
data Object the data to store with this state.
Source:
Throws:
An error if the bookmarkable state is too big.
Example

Store a color in the URL:

try {
   var color = '#99CCFF';
   router.store(color);
   $('#chapter').css('background', color);
}
catch (error) {
   oj.Logger.error('Error while storing data: ' + error.message);
}