Building a Javascript single page application without framework
Tags: javascript, es6, framework
Published: 2020-03-05 17:10:28

<!-- wp:paragraph -->
<p>Hello guys here we come with new tutorial for how to create single page application without framework.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>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.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>First of all,</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>What is single page application?</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p>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</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Let's get started</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>NOTE</strong>: 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.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>so finally let's start</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Creating a single page application</h2>
<!-- /wp:heading -->

<!-- wp:paragraph -->
<p> We will implement Single page application with location hash approach and using webpack for bundling and compiling purpose</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Setting up a project</h3>
<!-- /wp:heading -->

<!-- wp:list {"ordered":true} -->
<ol><li>Run 'npm init' command for creating package.json</li><li>Install webpack dependencies like below<ol><li>npm install webpack webpack-cli -D</li></ol></li></ol>
<!-- /wp:list -->

<!-- wp:paragraph -->
<p>after that let's create folder structure</p>
<!-- /wp:paragraph -->

<!-- wp:image {"id":239,"width":345,"height":316,"sizeSlug":"large"} -->
<figure class="wp-block-image size-large is-resized"><img src="https://techboxweb.com/wp-content/uploads/2020/03/image.png" alt="" class="wp-image-239" width="345" height="316"/></figure>
<!-- /wp:image -->

<!-- wp:paragraph -->
<p>As you can see above we have created folder structure in that we have components folder in which we will keep our javascript files</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>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)</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>views folder will contain HTML files which will be needed to load on routing</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>index.html and index.js are entry points for our application</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>webpack.config.js is for writing webpack configuration</p>
<!-- /wp:paragraph -->

<!-- wp:heading -->
<h2>Index.html</h2>
<!-- /wp:heading -->

<!-- wp:code -->
<pre class="wp-block-code"><code>&lt;!DOCTYPE html>
&lt;head>
&lt;/head>
&lt;body>
    &lt;a href="#detail">Details&lt;/a>
    &lt;a href="#landing">Landing&lt;/a>
    &lt;section id="app">
    &lt;/section>
&lt;/body>
&lt;/html></code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>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</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>section with id 'app' is taken for loading routes dynamically under this.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Now, let's create routing files</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Route.js</h3>
<!-- /wp:heading -->

<!-- wp:code -->
<pre class="wp-block-code"><code>export class Routes {
    constructor(viewObj, isDefaultRoute) {
        this.viewObj = viewObj;
        this.isDefaultRoute = isDefaultRoute;
    }
    isActiveRoute(hashPath) {
        return hashPath.replace('#', '') === this.viewObj.path
    }
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>In the above code, we have properties which will require for individual routes</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>like viewObj will contain path and URL properties like below</p>
<!-- /wp:paragraph -->

<!-- wp:code -->
<pre class="wp-block-code"><code>{
 path: 'path',
 templateUrl : 'path/to/html'
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>isDefaultRoute will decide which one to be loaded by default if any path doen't match with loacation hash</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>isActiveRoute function will let you know the currently active route</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p> Now let's create Router.js which will take care functionality of routing</p>
<!-- /wp:paragraph -->

<!-- wp:heading {"level":3} -->
<h3>Router.js</h3>
<!-- /wp:heading -->

<!-- wp:code -->
<pre class="wp-block-code"><code>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 &lt; 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 &amp;&amp; this.status === 200) {
                scope.routeElement.innerHTML = this.responseText;
            }
        };
        xhttp.open('GET', url, true);
        xhttp.send();
    }
}</code></pre>
<!-- /wp:code -->

<!-- wp:paragraph -->
<p>It is the main class where we have the main magic of the code</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Here 4 functions and one constructor</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>Constructor</strong>: constructor accepting 2 parameters in which 1st one is routing configuration which of <strong>Routes </strong>class type and another one is a root element where our view will be loaded dynamically</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>initialize</strong> function is for attaching hashchange event listener which will be fired when location hash changes</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p> hashChange function calls every time when hashchange event fires and in that we match with correct route and load that URL</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>navigate</strong> function takes care of loading HTML with the help of ajax request</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p><strong>getPathAndRouteMapping</strong> function is used for persisting a mapping of path and URL.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p></p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>Please check <a href="https://github.com/nitinhepat/spa-without-framework">this </a>code repository for whole code</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>In above example we just covered basics of routing we can make it advance. Before going forward at least you guys start with this.</p>
<!-- /wp:paragraph -->