I needed a lightweight routing component in one of my AngularJS projects. The existing solutions like UI router and the Angular Router are way to heavy for my requirements. I only had the following requirements:
- One controller/view loaded for #pageA
- Another controller/view loaded for #pageB
I decided to write my own router component, to be sure the routing component has an absolutely minimum footprint (around 2 kb, unminified).
The basic HTML structure:
<div ng-controller="RoutingController as router"> <div ng-if="router.route === 'pageA'" ng-controller="PageAController"></div> <div ng-if="router.route === 'pageB'" ng-controller="PageBController"></div> </div>
The RoutingController uses a Router factory and a RouterEventsService, and is defined like this:
function RoutingController($scope, Router, RoutingEventsService) { var controller = this; controller.route = 'pageA'; var router = new Router; router.addRoute('pageA'); router.addRoute('pageB'); RoutingEventsService.listen(locationHashChanged); $scope.$on('$destroy', function() { RoutingEventsService.stop(locationHashChanged); }); function locationHashChanged() { var currentRoute = router.route(window.location.hash); if (!currentRoute) { return false; } // scroll to top after switching route $('html,body').animate({scrollTop: 0}, 50); controller.route = currentRoute.name; $scope.$apply(); // RoutingEvents are defined outside the angular scope } }
The Router factory function is defined like this:
function Router() { var m = this; m.routes = []; m.default = null; m.addRoute = function(name) { var route = {name: name}; m.routes.push(route); if (!m.default) { m.default = route; } }; m.getDefault = function() { return m.default; }; m.route = function(hash) { var matched; angular.forEach(m.routes, function(route) { if (hash === '#/' + route.name) { matched = route; } }); if (!matched) { matched = m.getDefault(); } return matched; }; }
The RouterEventsService is defined like this:
function RoutingEventsService($window) { var service = this; service.listen = function(fn) { if ($window.addEventListener) { $window.addEventListener('load', fn); $window.addEventListener('hashchange', fn); } else if($window.attachEvent) { $window.attachEvent('load', fn); $window.attachEvent('hashchange', fn); } }; service.stop = function(fn) { if ($window.removeEventListener) { $window.removeEventListener('load', fn); $window.removeEventListener('hashchange', fn); } else if($window.detachEvent) { $window.detachEvent('load', fn); $window.detachEvent('hashchange', fn); } }; }