31K Views

Single Page Applications: The Frontier of User-Experience

The web as a platform is constantly growing. Naturally, the complexity of applications built for the web is constantly on the rise as well. For years, we have gotten along just fine with building traditional web apps with full page reloads whenever making a transition from one page to another. But the web is more demanding now, and there always seems to be a gap between the kind of user experience web applications offers as opposed to one offered by native desktop applications.

When building a web application, there are generally two types of applications that we can build: Single Page Applications (SPA), and Multi Page Applications (MPA). Everyone is familiar with the idea of MPA, it’s the traditional web app we all grew up building. SPA is the new kid on the block, with the ultimate goal of providing a user experience similar to that of desktop/mobile applications.

Building A Single Page Application:

The idea behind a SPA-based website is to load all the necessary code with a single page load and then to dynamically update that page through JavaScript as the user interacts with your application. With this kind of system in place, the page should never have to reload unless the user does so manually.

To build such an application, we will be using only jQuery. We won’t be bothering much with the server end of the application, since the majority of our application logic will be residing in front end in the form of JavaScript code.

Let’s take a look at the index.html file. This will be the only .html file we will be using in our application. All the contents of our web app will be directed through this file.

<!DOCTYPE html>
<html>
    <head>
        <title>My Application</title>
    </head>
    <body>
		<div class="app-container">
		    <h1>Hello World!</h1>
		</div>
    </body>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <script src="spa.js"></script>
    <script src="app.js"></script>
</html>

The html document consists of three important parts, so lets quickly glance over them:

  • spa.js: JavaScript code residing in this script will act as our SPA framework for building our application
  • app.js: JavaScript code residing in this script will contain the main logic for our application
  • .app-container: This will the document node in our HTML document in which we will be injecting the view for our application

Let’s take a look over at spa.js:

function AppRouter() {
    this.routeConfig = {};
    this.routeListing = {
        static: {}, // For Static Route Paths
    };

    this.getAllRoutes = function() {
        return this.routeConfig;
    };

    this.getStaticPathRoute = function(pathInformation) {
        var matchedRouteName = null;
        $.each(this.routeListing.static, function(routeName, routePath) {
            if (routePath == pathInformation) {
                matchedRouteName = routeName;
                return false;
            }
        });

        return matchedRouteName;
    }


    this.getCurrentRoute = function() {
        // Assuming we're on app_dev
        var currentPath = window.location.pathname;
        var pathInformation = currentPath.replace('/symfony/spaProject/web/app_dev.php/', '/');

        // Check if current url matches with any static routes
        var matchedRouteName = this.getStaticPathRoute(pathInformation);
        if (matchedRouteName != null) {
           return this.routeConfig[matchedRouteName];
        } else {
            // Check for dynmaic routes
            console.log('route not found');
        }

        return null;
    }

    this.addRoutingConfiguration = function(configuration) {
        this.routeConfig[configuration.routeName] = {
            model: (configuration.hasOwnProperty('model') ? configuration.model : {}),
            view: configuration.view,
        };

        if (configuration.type == 'dynamic') {
            this.routeListing.dynamic[configuration.routeName] = configuration.pathName;
        } else {
            this.routeListing.static[configuration.routeName] = configuration.pathName;
        }
    }
};

function AppView(appRouter) {
    this.initialize = function() {
        this.route = appRouter.getCurrentRoute();
        this.view = this.route.view;

        if (this.view.hasOwnProperty('init')) {
            // Initialize Model
            var tempModel = this.route.view.init();
            this.view.model = tempModel;
        }
    }

    this.render = function() {
        var templateString = this.view.loadTemplate(this.view.model);

        // Inject into view
        $('.app-container').empty();
        $('.app-container').append(templateString);
    }

    // Updates Browser URL and History State
    this.updateRoute = function(pathInformation){
        var newPathURL = '/symfony/spaProject/web/app_dev.php' + pathInformation;
        stateObj = {page: 'home'};
        window.history.pushState(stateObj, 'Default', newPathURL);

        this.initialize();
        this.render();
    };

    // For Local Reference
    var self = this;

    $('body').on('click', 'a', function(e) {
        e.preventDefault();
        var targetElement = e.currentTarget;

        self.updateRoute(targetElement.pathname);
    });
};

spa.js consists of two functions AppRouter() & AppView() which will act as an object. AppRouter will be used to initialize our routes (we’ll get to that in a second), and AppView will be used to render our application’s view.

Router:

Unlike MPA, where our application is divided into multiple pages, we only have a single page in the case of SPA. The entire application is then managed through this single page. So there comes the obvious question of how we manage our routes, and when the load any particular pages. This will be done through the AppRouter. For each individual page for our application, we will create an object of AppRouter which will map to that given page, controlling the logic, loading the data from the server required for rendering the view for the respective page. So let’s take a look over at main.js and see how to go about that:

var homeRouter = {
    pathName: '/',
    routeName: 'home',
    routeType: 'static',
    routeTitle: 'Home',
    view: {
        events: {},
        loadTemplate: function(templateModel) {
            var templateBody = '';
            templateBody += '<h1>Home Page</h1>';

            return templateBody;
        }
    }
};

var welcomeRouter = {
    pathName: '/welcome',
    routeName: 'welcome',
    routeType: 'static',
    routeTitle: 'Welcome',
    view: {
        events: {},
        model: {
            username: 'Akshay Kumar',
        },
        loadTemplate: function(templateModel) {
            var templateBody = '';
            templateBody += '<h1>Welcome ' + templateModel.username + '</h1>';

            return templateBody;
        }
    }
};

$(document).ready(function() {
    // Load Routing
    var appRouter = new AppRouter();
    appRouter.addRoutingConfiguration(homeRouter);
    appRouter.addRoutingConfiguration(welcomeRouter);

    // Render View
    var appView = new AppView(appRouter);
    appView.initialize();
    appView.render();
});

As we can see over here, we have created two JSON Objects homeRouter, and welcomeRouter. If we take a look at our $(document).ready() function, once all the necessary resources have loaded, we first create a AppRouter object, then pass on all the available route configs for our application (homeRouter & welcomeRouter represented as JSON objects) to the AppRouter. Once we have included all the available routes, we then go on to create a AppView object, passing our AppRouter object as the constructor argument. Once we do that, all our routes our initialised into our application.

AppView works by checking the current URL in our web browser and then matches that to one of the many routes we created. Once a route is matched, then the route is loaded and it’s view accordingly. This cycle repeats whenever we make a transition from one view to another the URL in the browser updates.

Conclusion:

This is a very basic overview of the SPA pattern, but it can be extended to create a more promising real world application. We can extend this to fully implement the MVC pattern as well, specifically loading our model from the server and then injecting that into our view. There are no real benefits to building a Single Page Application other than to improve the user-experience (which is very important), but like anything that’s ever invented, every thing has its pros & cons. With SPA, you have to take into account many things, like the state of the application, security and managing browser history, as well as take in to consideration of maintaining such a system. I personally prefer to follow a more “hybrid” approach where the application is a mix between the MPA & SPA pattern. And as the case is with many JS based frameworks such as BackboneJS, AngularJS, etc… The support to build a Single Page Application is always there but is not always a necessity to build one. So use whatever works for you, and your end-users.

Category(s) Design
. . .

Leave a Comment

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


Be the first to comment.

css.php