Custom Router for Firebase jQuery App

custom-router-for-firebase-jquery-app

Custom Router for Firebase jQuery App

The Routing is showing different information in the single webpage with the help of URL or URL hash value. And today we are going to do a custom router for Firebase jQuery App that we had started in earlier post: Auth Schemes in Google Firebase.

In Front End, generally based on browser support we can leverage URL hash in almost all cases and full URLs in latest browsers.

So for now, to cover “almost all cases”, we will use the URL hashes for our router.

For URL hashes, the primary thing is window.location.hash and we would look for its change do changes in our application.

For this, browsers have the HashChangeEvent which allows to watch the changes in hash changes. You can read more about the event and it’s support in various browsers over here: https://developer.mozilla.org/en-US/docs/Web/API/HashChangeEvent.

It can be be bound in following three ways as:

window.onhashchange = function(e){
  //handle hash change
  console.log(e)
}

or

...

or

window.addEventListener("hashchange", function(e){
  //handle hash change
  console.log(e)
}, false);

And we will be using the `addEventListner` method on `window` object to bind our listners for `HashChangeEvent`.

Moving further, we would need a place on the page where our router can put the child pages as per the active route.

Basic Router

So we will create a mount point in our page where our router will fetch and replace the contents. To fetch the child page, we are going to use the jQuery’s `get()` function as we already have jQuery in our page. But you can any other library like qwest, fetch or axiom can be used to do the ajax to make it stand alone router.

Let’s take `#root` is out mount point and `render` is the name of the function which will do the fetch and replace of child pages. The child pages are in the `partials` directory parallel to our `js` directory and are named same as the hash with `.html` as an extension. Following is the code for that:

var mountPoint = '#root';
window.addEventListener('hashchange', function (e) {
  console.log(e);
  render(window.location.hash.replace(/[#]/, ''));
}, false);

var render = function(hashValue){
  $.get('partials/'+hashValue+'.html', function(data){
    $(mountPoint).empty().html(data);
  })
}

Controller Function for setup

The above code will work fine if we have data for view purpose only, but what if we want to have interactive child pages like forms. For such cases, the child pages will have their own event bindings that will need to be enforced when any child page is loaded.

So for that case, let’s make a binder function which will bind event after the fetch and replace has been done. And call that binder in render function. So render function will now look like:

var render = function(hashValue){
  $.get('partials/'+hashValue+'.html', function(data){
    $(mountPoint).empty().html(data);
    registerFormBindings();
  })
}

var registerFormBindings = function() {
  $('#submit').click(function(e){
    //validations
    $(form, mountPoint).validate();
  });
}

Controllers for States

Now our code is ready for a state/hash change. But it will do same `registerFormBindings` on all states. But child pages will obviously be different. So let’s assume that there are `login`, `register`, `add` and `list` states. So we can have an object; say `controllers`; which will have keys as state names and the value will hold the bindings function. This will look like as follows:

var render = function(hashValue){
  $.get('partials/'+hashValue+'.html', function(data){
    $(mountPoint).empty().html(data);
    controllers[hashValue]();
  })
}

var controllers = {
  login: function(){ /* ... */ },
  register: function() {
    $('#submit').click(function(e){
      //validations
      $(form, mountPoint).validate();
    });
  },
  add: function(){ /* ... */ },
  list: function(){ /* ... */ },
}

Looks good so far. But we can optimize the path of template and controller function for a state in following way:

var render = function(hashValue){
  $.get( routes[hashValue].path, function(data){
    $(mountPoint).empty().html(data);
    routes[hashValue].controller();
  })
}

var routes = {
  login: {
    path: 'partials/login.html',
    controller: function(){ /* ... */ },
  },
  register: {
    path: 'partials/register.html',
    controller: function() {
      $('#submit').click(function(e){
        //validations
        $(form, mountPoint).validate();
      });
    },
  },
  add: {
    path: 'partials/add.html',
    controller: function(){ /* ... */ },
  },
  list: {
    path: 'partials/list.html',
    controller: function(){ /* ... */ },
  },
}

After putting all of the above code together and giving it a form of an exportable module, the script can be crafted as follows:


Final Code

And the above code can be imported and used as follows in the required application.

var $ = require('jquery');
var Router = require('./router');

var appRouter = new Router({
  mountPoint: '#root',
  indexRoute: 'index',
  routes: {
    login : {
      path: 'login',
      template: 'partials/login.html',
      controller: function() {
        console.log('login controller function loaded');
      }
    },
    index : {
      path: 'index',
      template: 'partials/index.html',
      controller: function() {
        console.log('index controller function loaded');
      }
    },
    add : {
      path: 'add',
      template: 'partials/add.html',
      controller: function() {
        console.log('add controller function loaded');
      }
    }
  }
});

$(document).ready(function() {
  appRouter.listen();
});

We will be using the same for movie-db firebase app.


One thought on “Custom Router for Firebase jQuery App

Got Something To Say:

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

*