Super easy lightweight router in AngularJS

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);
        }
    };
}

Leave a Reply

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