September 22, 2020

Build a javascript single page application without a framework

Hello guys here we come with new tutorial for how to create single page application without framework.

Good developer always keen to understand how the single page application works internally because nowadays we are busy in learning frameworks but we don’t think how it works internally because we don’t want to but as a good programmer you should know in and out for a thing which you are learning.

First of all,

What is single page application?

Single page application is terminology in which you load the multiple pages dynamically without reloading an application, Like we have angular framework specifically made for single page application

Let’s get started

NOTE: We will be following the ES6 standard for coding. It means code which we are writing will not run directly on the browser, as of now browsers are not supporting most of the ES6 standard functionality directly but don’t worry we will add an appropriate compiler which will convert our code in browser understandable language.

so finally let’s start

Creating a single page application

We will implement Single page application with location hash approach and using webpack for bundling and compiling purpose

Setting up a project

  1. Run ‘npm init’ command for creating package.json
  2. Install webpack dependencies like below
    1. npm install webpack webpack-cli -D

after that let’s create folder structure

As you can see above we have created folder structure in that we have components folder in which we will keep our javascript files

libs folder is for the keeping our library files(might include routing js files which will be developed by us for single page application purpose)

views folder will contain HTML files which will be needed to load on routing

index.html and index.js are entry points for our application

webpack.config.js is for writing webpack configuration

Please subscribe for web development tutorials

Index.html

<!DOCTYPE html>
<head>
</head>
<body>
    <a href="#detail">Details</a>
    <a href="#landing">Landing</a>
    <section id="app">
    </section>
</body>
</html>

As you can see above, In index.html we have taken two href tag in which we have routing for detail and landing links, so here the moto is to load view associated with this links

section with id ‘app’ is taken for loading routes dynamically under this.

Now, let’s create routing files

Route.js

export class Routes {
    constructor(viewObj, isDefaultRoute) {
        this.viewObj = viewObj;
        this.isDefaultRoute = isDefaultRoute;
    }
    isActiveRoute(hashPath) {
        return hashPath.replace('#', '') === this.viewObj.path
    }
}

In the above code, we have properties which will require for individual routes

like viewObj will contain path and URL properties like below

{
 path: 'path',
 templateUrl : 'path/to/html'
}

isDefaultRoute will decide which one to be loaded by default if any path doen’t match with loacation hash

isActiveRoute function will let you know the currently active route

Now let’s create Router.js which will take care functionality of routing

Router.js

export class Router {
    constructor(routes, routeElement) {
        this.routes = routes;
        this.routeElement = document.getElementById(routeElement);
        this.initialize();
        this.hashChanged();
    }
    getPathAndRouteMapping() {
        const routeMapping = {};
        for (let objKey in this.routes) {
            routeMapping[this.routes[objKey].viewObj.path] = this.routes[objKey].viewObj.url;
        }
        return routeMapping;
    }
    initialize() {
        window.addEventListener('hashchange', (e) => {
            this.hashChanged()
        })
    }
    hashChanged() {
        const locationHash = window.location.hash;
        for (let i = 0; i < this.routes.length; i++) {
            const route = this.routes[i];
            if (route.isActiveRoute(locationHash.substr(1))) {
                this.navigate(route.viewObj.path)
            }
        }
    }
    navigate(path) {
        const pathRouteMapping = this.getPathAndRouteMapping();
        const url = pathRouteMapping[path];
        const xhttp = new XMLHttpRequest();
        let scope = this;
        xhttp.onreadystatechange = function() {
            if (this.readyState === 4 && this.status === 200) {
                scope.routeElement.innerHTML = this.responseText;
            }
        };
        xhttp.open('GET', url, true);
        xhttp.send();
    }
}

It is the main class where we have the main magic of the code

Here 4 functions and one constructor

Constructor: constructor accepting 2 parameters in which 1st one is routing configuration which of Routes class type and another one is a root element where our view will be loaded dynamically

initialize function is for attaching hashchange event listener which will be fired when location hash changes

hashChange function calls every time when hashchange event fires and in that we match with correct route and load that URL

navigate function takes care of loading HTML with the help of ajax request

getPathAndRouteMapping function is used for persisting a mapping of path and URL.

Please check this code repository for whole code

In above example we just covered basics of routing we can make it advance. Before going forward at least you guys start with this.

If you like please share this post and follow me on twitter for more updates

Leave a Reply

Your email address will not be published. Required fields are marked *