Programmatic Navigation
index.html
Listening anchor events
const NAV_A_SELECTOR = 'a[data-navigation]';
router.start = () => {
checkRoutes();
window.setInterval(checkRoutes, TICKTIME);
document
.body
.addEventListener('click', e => {
const { target } = e;
if (target.matches(NAV_A_SELECTOR)) {
e.preventDefault();
router.navigate(target.href);
}
})
return router;
}
router.navigate
router.navigate = fragment => {
window.location.hash = fragment
}
Route Parameters
freshdesk.com/tickets/:id
freshdesk.com/tickets/123
routes.js
const detail = (params) => {
const { id } = params
container.textContent = `This is Detail Page with Id ${id}`;
}
const anotherDetail = (params) => {
const { id, anotherId } = params
container.textContent = `This is another Detail Page
with Id ${id} and AnotherId ${anotherId}`;
}
Defining Routes with parameters
router
.addRoute('#/', pages.home)
.addRoute('#/list', pages.list)
.addRoute('#/list/:id', pages.detail)
.addRoute('#/list/:id/:anotherId', pages.anotherDetail)
.setNotFound(pages.notFound)
.start()
Extracting Parameter names
#/list/:id/:anotherId
/:(\w+)/g
[ 'id', 'anotherId' ]
Matching route with parameters
#/list/:id/:anotherId
^#\/list\/([^\\/]+)\/([^\\/]+)$
Extracting Parameters Name from Fragments
const ROUTE_PARAMETER_REGEXP = /:(\w+)/g
const URL_FRAGMENT_REGEXP = '([^\\/]+)'
router.addRoute = (fragment, component) => {
const params = []
const parsedFragment = fragment
.replace(
ROUTE_PARAMETER_REGEXP,
(match, paramName) => {
params.push(paramName)
return URL_FRAGMENT_REGEXP
})
.replace(/\//g, '\\/')
routes.push({
testRegExp: new RegExp(`^${parsedFragment}$`),
component,
params
})
return router
}
Route entry in the Registry
#/list/:id/:anotherId
{
"testRegExp": ^#\/list\/([^\\/]+)\/([^\\/]+)$,
"component": pages.anotherDetail,
"params": ['id', 'anotherId']
}
Populate the route params from the current fragment
const extractUrlParams = (route, windowHash) => {
if (route.params.length === 0) {
return {};
}
const params = {};
const matches = windowHash.match(route.testRegExp);
matches.shift();
matches.forEach((paramValue, index) => {
const paramName = route.params[index]
params[paramName] = paramValue
});
return params;
}
checkRoutes
const checkRoutes = () => {
const { hash } = window.location;
const currentRoute = routes.find(route => {
const { testRegExp } = route;
return testRegExp.test(hash);
});
if (!currentRoute) {
notFound();
return;
}
const urlParams = extractUrlParams(
currentRoute,
window.location.hash
);
currentRoute.component(urlParams);
}
Demo
Downsides of Hash-based routing
URL based routing
History API
Manipulate the user's browsing history
History API
back() | Goes to the previous page in the history. |
forward() | Goes to the next page in the history. |
go(index) | Goes to a specific page in the history. |
pushState(state, title, URL) | Pushes the data in the history stack and navigate to the provided URL. |
replaceState(state, title, URL) | Replaces the most recent data in the history stack and navigates to the provided URL. |
checkRoutes
const { pathname } = window.location;
if (lastPathname === pathname) {
return;
}
router.navigate
router.navigate = path => {
window
.history
.pushState(null, null, path)
}
Demo
Navigo
Created by Krasimir Tsonev
GithubAdding Navigo to our app
Using Navigo in our router.js
export default () => {
const navigoRouter = new window.Navigo()
const router = {}
router.addRoute = (path, callback) => {
navigoRouter.on(path, callback)
return router
}
router.setNotFound = cb => {
navigoRouter.notFound(cb)
return router
}
router.navigate = path => {
navigoRouter.navigate(path)
}
router.start = () => {
navigoRouter.resolve()
return router
}
return router
}
index.html
Demo
When to use What?
Hash-based | URL-based | |
Older Browsers | ✅ | ❌ |
Browser History | ❌ | ✅ |
Server-side Rendering | ❌ | ✅ |
Backend interactions | ❌ | ✅ |
Ember.js
// Hash based routing
ENV.locationType = "hash";
// URL based routing
ENV.locationType = "history";
Automatic routing
// Modern Browsers => History API
// Older Browsers => Hash based routing
ENV.locationType = "auto";
React
react-routerHash based routing:
URL based routing ( History API)
Vue.js
vue-routerHash based routing (default):
const router = new VueRouter({
mode: 'hash',
});
HTML5 History Mode
const router = new VueRouter({
mode: 'history',
});
References:
Slides
https://rajasegar.github.io/csr-slides/Thank you!