RoutieSPA

In this world of all-singing, all-dancing client-side MV* frameworks it's easy to over complicate things. Sometimes you need to rethink the problem and use appropriate technology which does just what you need it to. For example, say I have a simple Single-Page Application (SPA) to build. Each view corresponds to a Bootstrap Nav of which the view will be loaded into a container of some sort:

<!DOCTYPE html>  
<html lang="en">  
<head>  
    <meta charset="utf-8" />
    <title>Routie &hearts; Bootstrap</title>
    <link href="css/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
</head>  
<body>  
    <main class="container">
        <ul class="nav nav-tabs nav-justified" id="paging">
            <li><a href="#/home">Home</a></li>
            <li><a href="#/profile">Profile</a></li>
            <li><a href="#/messages">Messages</a></li>
        </ul>
        <section id="pvContent"></section>
    </main>

    <!-- Templates -->
    <template data-href="/home">Home Page</template>
    <template data-href="/profile">Profile Page</template>
    <template data-href="/messages">Messages Page</template>

    <!-- Scripts -->
    <script src="js/jquery.min.js"></script>
    <script src="js/routie.min.js"></script>
    <script src="js/app.js"></script>
</body>  
</html>  

Enter routie. What we can do with routie is bind our hashpaths to custom behaviour. The magic happens in app.js when we bind routie to the wildcard (*) route:

// app.js
"use strict";

routie('*', function (path) {  
    // Load the html from template
    var tmplContent = $('template[data-href="' + path + '"]').html();
    $('#pvContent').html(tmplContent);

    // If any tab is selected as active, remove active class
    $('#paging > li.active').removeClass('active');

    // Find the li with an anchor with the path in it
    $('#paging > li > a[href="#' + path + '"]')
        .parent()
        .addClass('active');
});

When a user clicks on a tab, it changes the hashpath which routie observes and loads the content of a template associated with the path. There's only one caveat: what if there's no hash when the page is loaded?

// Set default hashroute to '/home' if no hash defined
if (location.hash === '') {  
    location.hash = '/home';
}

In just a few sweet lines of js we've got our templates being loaded into our view container without a full page refresh. You'll also notice that if you refresh the page the view previously selected will be shown, no additional complexity needed!

Let's do something a little more involved: when the user clicks on the messages tab, we will render out a table on the left side of the view and on the right hand side will be the message content:

The client-side js is super simple:

routie('/messages/:id', function (id) {

    var messageData = [
        "",
        "Hey Sam, Is that report ready?<br/>",
        "Yo Sam,<br/><br/>Let's get crunked tomorrow night!<br/><br/>- Curly",
        "Are you interested in losing weight???"
    ];

    $('#msgContent').html(messageData[id]);
})
<template data-href="/messages">  
    <div class="row" style="padding:10px;">
        <nav class="col-lg-3">
            <ul class="list-group">
                <li class="list-group-item">
                    <span class="badge">3</span>
                    <a href="#/messages/1">Bob Jones</a>
                </li>
                <li class="list-group-item">
                    <span class="badge">1</span>
                    <a href="#/messages/2">Curly Katz</a>
                </li>
                <li class="list-group-item">
                    <span class="badge">1k+</span>
                    <a href="#/messages/3">Johnny D.</a>
                </li>
            </ul>
        </nav>
        <section class="col-lg-7">
            <blockquote id="msgContent"></blockquote>
        </section>
    </div>
</template>  

you would replace the message data array with a call to your service endpoint and update the content of the list-group dynamically.

You can find the full source for this fake-SPA on GitHub.