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):
- Check if the link is valid and eligible for PJAX. If yes, prevent the normal browser behavior.
- Change the URL using the push state API.
- Start fetching the new page via a XMLHttpRequest.
- Create a new transition instance.
- 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 thecontainerSelector
option on theview
binder wich is[data-namespace]
by default). - The transition instance will take care of hiding the old container and showing the new one.
- 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 |
Before you click on this button, make sure that the preview of the view binder example below is open.
Click to open the page in a new tab.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 |
This is the content of the element with the rv-view binder.
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 |