Router Module Reference

About

The router module is based on barba.js v1 but was ported to typescript and changed a bit for the needs of this module. To understand how this module works in detail, we still recommend to read the documentation of barba.js.

How it works

The router module uses PJAX (aka push state ajax) to enhance the user's experience.

This technique consist of preventing the normal link behavior (or alternatively via the route binder), changing the browser url manually, and manually injecting the new content in the page. In this way there will be no browser "hard refresh" as it is known from other SPA frameworks.

Unlike other SPA frameworks, however, no changes are necessary of how the templates are delivered. Therefore, the route module is also suitable to use with classic CMS systems such as Wordpress, OctoberCMS, Shopify and many more. On the server side your pages can be served normally. The router module works as ehnancement for your website, so everything else can be work normally without Javascript.

Here is a walkthrough of what happens when the user clicks a link (or the route binder):

  1. Check if the link is valid and eligible for PJAX. If yes, prevent the normal browser behavior.
  2. Change the URL using the push state API.
  3. Start fetching the new page via a XMLHttpRequest.
  4. Create a new transition instance.
  5. As soon the new page is loaded, the router module parses the new HTML (taking the content of the view binder) and puts the new content on the DOM inside container element (passed as the containerSelector option on the view binder wich is [data-namespace] by default).
  6. The transition instance will take care of hiding the old container and showing the new one.
  7. As soon the transition is finished, the old container element is removed from the DOM.

Why

Using this technique will bring numerous benefits:

  • Possibility to create nice transition between pages enhancing the user's experience.
  • Reduce HTTP requests. (why reload the css/js at each page change?)
  • Possibility to speed up the navigation using prefetch and cache.
  • Works well with classic CMS systems.
  • Your page feels like an modern app

Install

npm install --save @ribajs/router

Regist

To regist the module include import routerModule from '@ribajs/router'; in your main.ts file and regist the module with riba.module.regist(routerModule);:

import { Riba } from '@ribajs/core';
import { ready } from '@ribajs/utils/src/dom';
import routerModule from '@ribajs/router';
const riba = new Riba();
const model = {};
riba.module.regist(routerModule);
ready(() => {
  riba.bind(document.body, model);
});

Templates

So that the module works all templates (which can be called via the router module) must match the following schema:

<!-- here your normal doctype, head and body structure -->
<div id="main" rv-view="">
  <div data-namespace="index">
    ...
  </div>
</div>

The value of data-namespace can (and should) be different on each template. By default, all data attributes are automatically assigned to the template's riba model.

Events

During all the lifecycle of the page transition, the router module will emit a series of events, with useful information:

Name Arguments Description
linkClicked HTMLElement, MouseEvent The user click on a link elegible for PJAX.
initStateChange currentStatus The link has just been changed.
newPageReady viewId, currentStatus, prevStatus, HTMLElementContainer, newPageRawHTML, containerDataset isFirstPageLoad The new container has been loaded and was injected
transitionCompleted viewId, currentStatus [, prevStatus] The transition has just finished and the old Container has been removed from the DOM.

currentStatus and prevStatus are plain objects with the url of the page and eventually the namespace:

export interface State {
  url: string;
  namespace?: string | null;
}

To listen for an event, it's as simple as:

import { EventDispatcher } from '@ribajs/core';

const dispatcher = new EventDispatcher('main');

dispatcher.on('newPageReady', (viewId: string, currentStatus: State, prevStatus: State, container: HTMLElement, newPageRawHTML: string, dataset: any, isFirstPageLoad: boolean) => {
  // your listener
});

Binders

route

Loads a link and injects the content insite the view container, in addition, the link is pre-loaded on a mouse over. This binder is like a normal link in barba.js but allows a bit more control.

Instead of the URL you can also pass some options to the binder as a object (by keypath) or as a json string

Option name Default Description
url The url you want to load on a click
viewId 'main' The id of the view in which the content should be replaced
removeAfterActivation false If you wish to remove the element from the DOM after activation

route-class-[classname]

Tests the url with the current location, if the url is equal to the current location this element gets the class

parent-route-class-[classname]

Tests the url with the current location, if the current location starts with the url this element gets the [classname] class

view

This binder is the heart of the router module. If you want to develop a single-page application then the main content should use this binder to dynamically exchange its content. This binder is what the barba-wrapper and barba-container are in barba.js (see barba install documentation). As a bigger example this site also uses this binder to dynamically load its content. Your application can also have multiple view binders, only the ids need to be different. In the example below we also use an additional view binder (next to our main view binder) to demonstrate the functionality.

The binder attribute value accepts an object or json string with the following available options:

Option name Type Default Description
viewId string 'main' The id of the view, must be unique and is only needed with multiple view binders, should be set via the id attribute
containerSelector string [data-namespace] if viewId is 'main' otherwise #${viewId} > *:first-child Selector of the container child, here the HTML content is replace
action string 'replace' Replaces the old container content with the new one
scrollToTop boolean true if viewId is 'main' otherwise false Auto scrolls to the top of the page when the new page is loading
listenAllLinks boolean true if viewId is 'main' otherwise false Loads the content of all links, even without the route binder
listenPopstate boolean true if viewId is 'main' otherwise false Responds to the browsers go back button and loads the content of the previous page
scrollToAnchorHash boolean true if viewId is 'main' otherwise false Auto scrolls to the anchor id passed by the url hash value
datasetToModel boolean true if viewId is 'main' otherwise false Binds the values passed as data attributes to the model / scope of this binder
parseTitle boolean true if viewId is 'main' otherwise false Parses the <title></title> and replace the tab name
changeBrowserUrl boolean true if viewId is 'main' otherwise false Changes the browser URL when the new page is loading
prefetchLinks boolean true if listenAllLinks is true otherwise false Loads the content of the url on mouse over to speed up the page loading
transition Transition HideShowTransition The transition object e.g. for animations

view-static

Loads the content of the url with pjax and replaces this with the inner html of the element

Option name Type Default Description
url string The url whose content you want to display
viewId string handleized url The id of the view, must be unique and is only needed with multiple view binders, should be set via the id attribute
containerSelector string [data-namespace] Selector of the container child, here the HTML content is replace
transition Transition HideShowTransition The transition object e.g. for animations