Single page apps are becoming the hot cake in the web industry, Everyone wants to build SPA or Single page apps. In this article, we will do a quick rundown SPA using jQuery and without using any MV* frameworks like React, Angular, Vue etc.
Overview
Since we are building a spa and we don’t want any page refreshes, we’ll use sammy.js for routing. Sammy is a 5.2K jQuery dependent library. A typical Sammy routing script is like:
01 02 03 04 05 06 07 08 09 10 11 12 13 | var app = $.sammy( function () { this .get( '#/' , function () { //your function }); this .get( '#about/' , function () { //your function }); this .get( '#contact/' , function () { //your function }); }); app.run(); |
first we have to initialize the application using $.sammy and stored the instance into app. In sammy we can define a route using
1 2 3 | this .get( 'path/' , function (){ ... }); |
Each route has a callback function where we can write our logic, bind the data specific to each view/page/screen, As each route is representing a view.
After defining all routes we can bootstrap our spa using app.run();
Our blog App
To clear the concept lets jump into a somewhat more realistic example. We’re just going to make a simple blog. Which has the main page(ie, Home) and About page. In homepage or index page we’ll have a list of blogs, clicking each item will take us to blog details page. Meanwhile, you can check the code here.
We’ll be using static JSON data blog list and we’ll use Sammy templating plugin to separate the each view.
File structure
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | - index.html <!-- main layout --> - app.js <!-- stores all our routing logic --> - css --- style.css - js --- jquery-1.11.3.min.js --- sammy.min.js --- sammy.template.js - data --- articles.json - templates <!-- the templates pages that will be injected into the main layout --> --- article.template --- article-detail.template --- about.template |
Markup
We’ll be using HTML5 boilerplate template for the markup
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <! DOCTYPE html> < html > < head > < meta name = "viewport" content = "width=device-width, initial-scale=1.0" > < script src = "js/jquery-1.11.3.min.js" type = "text/javascript" ></ script > < script src = "js/sammy.min.js" type = "text/javascript" ></ script > < script src = "js/sammy.template.js" type = "text/javascript" ></ script > < link rel = "stylesheet" href = "css/style.css" /> < script src = "app.js" ></ script > </ head > < body > < div class = "header-container" > < header class = "wrapper clearfix" > < nav > < ul > < li >< a href = "#/" >Home</ a ></ li > < li >< a href = "#/about/" >About</ a ></ li > <!-- defining nav url according to route--> </ ul > </ nav > </ header > </ div > < div class = "main-container" > < div class = "main wrapper clearfix" > < div id = "app" > <!-- template will be injected here --> </ div > </ div > </ div > </ body > </ html > |
Defining Routes
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | //app.js ( function ($) { var app = $.sammy( '#app' , function () { this .use( 'Template' ); this .around( function (callback) { var context = this ; this .load( 'data/articles.json' ) .then( function (items) { context.items = items; }) .then(callback); }); this .get( '#/' , function (context) { context.app.swap( '' ); $.each( this .items, function (i, item) { context.render( 'templates/article.template' , {id: i, item: item}) .appendTo(context.$element()); }); }); this .get( '#/about/' , function (context) { var str=location.href.toLowerCase(); context.app.swap( '' ); context.render( 'templates/about.template' , {}) .appendTo(context.$element()); }); this .get( '#/article/:id' , function (context) { this .item = this .items[ this .params[ 'id' ]]; if (! this .item) { return this .notFound(); } this .partial( 'templates/article-detail.template' ); }); this .before( '.*' , function () { var hash = document.location.hash; $( "nav" ).find( "a" ).removeClass( "current" ); $( "nav" ).find( "a[href='" +hash+ "']" ).addClass( "current" ); }); }); $( function () { app.run( '#/about/' ); }); })(jQuery); |
First, we have initialized our app in “#app” div, where we’ll inject different template according to route path. We also mentioned that we’ll be using the sammy template engine.
1 | this.use('Template'); |
we have fetched blog data from articles.json using Jquery load(you can also use $.get or $.post) method and stored into the context variable.
Now time to define our for route or index page using “#/”
1 2 3 4 5 6 7 | this .get( '#/' , function (context) { context.app.swap( '' ); $.each( this .items, function (i, item) { context.render( 'templates/article.template' , {id: i, item: item}) .appendTo(context.$element()); }); }); |
we already have data in context, we are looping through all the data and rendering it in article.template. we are also using context.app.swap(”); method just need to clear the content area (ie, #app) before rendering the templates.
1 2 3 4 5 | < article > < section > < a href="#/article/<%= id %>">< h2 ><%= item.title %></ h2 ></ a > </ section > </ article > |
as we are using templating engine so we can write dynamic value using <%= yourdata %>. you can see we have also linked article details page for each article using #/article/<%= id %>
It will take us to article-detail.template, where we can show article image, excerpt etc.
Behind the scene, we also defined a route for article details page in app.js. we are getting article index as an URL parameter and passing the data to article-detail.template.
1 2 3 4 5 | this .get( '#/article/:id' , function (context) { this .item = this .items[ this .params[ 'id' ]]; if (! this .item) { return this .notFound(); } this .partial( 'templates/article-detail.template' ); }); |
Similarly, we have also created a static page called “about” and rendering into about.template.
1 2 3 4 5 6 | this .get( '#/about/' , function (context) { var str=location.href.toLowerCase(); context.app.swap( '' ); context.render( 'templates/about.template' , {}) .appendTo(context.$element()); }); |
Done. oops no, we forgot to bootstrap our app using app.run() where you can also mention your default route. If want to open about page first then you need to define app.run(‘#/about/’).
1 2 3 | $( function () { app.run( '#/about/' ); }); |
if you want to make some operation before calling each route you can use before method. here we are selecting current nav menu according to current route path.
1 2 3 4 5 | this .before( '.*' , function () { var hash = document.location.hash; $( "nav" ).find( "a" ).removeClass( "current" ); $( "nav" ).find( "a[href='" +hash+ "']" ).addClass( "current" ); }); |
So this was a very simple article on getting started with jquery routing. Now you can go ahead and create larger single page applications. One thing remember routing would need a web server running, either you can use a PHP server or node server. You can also try firefox. Chrome has blocked AJAX requests to any protocol other than http://. or https://, so if you’re just running this code on your local machine the app won’t work as the local file has link started with file://.
0 Comments