johnoscott
7/16/2013 - 5:35 AM

$namedRoute.js

(function(angular) {
    'use strict';


    /*
        Usage:
        -----
        
        FILE --app.js--
        
        angular.module('RouteExample')
        .config(['$namedRouteProvider', function ($routeProvider) {
            $routeProvider
                .when('/', {
                    name: 'login',
                    templateUrl: 'views/login.html',
                    controller: 'LoginCtrl'
                })
                .when('/:client', {
                    name: 'home',
                    templateUrl: 'views/dashboard.html',
                    controller: 'DashboardCtrl'
                })
                .when('/:client/profile', {
                    name: 'profile',
                    templateUrl: 'views/profile.html',
                    controller: 'ProfileCtrl'
                })
                .otherwise({
                    redirectTo: '/'
                });
        }]).
        controller('AppCtrl', ['$scope', '$route', function($scope, $route) {
            // Some global helper functions for routing
            $scope.goto = function(page, optionalParams) {
                $route.to[page](optionalParams);
            };
            
            $scope.login = function() {
                $route.to.login();
            };
        }]);
        
        
        FILE --dashboard.html--
        
        <!--
            note that we are at /:client/ in this view
            To goto the profile page we need to goto /:client/profile maintaining our client param
            This named route provider does that for you, maintaining any existing params in the new route
              whilst also allowing new params to be passed in as required or to override existing params
         -->
        <span ng-click="login()">Logout</span>
        <nav>
            <ul>
                <li ng-click="goto('home')" ng-class="{active: $route.current.name == 'home'}">Dashboard</li>
                <li ng-click="goto('profile')" ng-class="{active: $route.current.name == 'profile'}">My Profile</li>
            </ul>
        </nav>
    */


    angular.module('Core')

        .provider('$namedRoute', ['$routeProvider', function($routeProvider) {
            var namedRoutes = {},
                paramMatcher = /(?:\:)(.*?)(?:(\/|$)\/?)/gm;

            this.when = function(path, route) {
                if (route.name) {
                    var altPath = path,
                        matches = altPath.match(paramMatcher) || [],
                        param,
                        i;

                    // this converts paths '/:param1/:param2' to '/{{param1}}/{{param2}}/'
                    for (i = 0; param = matches[i]; i += 1) {  // this will break on undefined
                        altPath = altPath.replace(param, '{{' + param.replace(/\:|\//gm, '') + '}}/');
                    }

                    namedRoutes[route.name] = altPath;
                }

                // Update the actual route provider
                $routeProvider.when(path, route);

                return this;
            };

            this.otherwise = $routeProvider.otherwise;

            this.$get = ['$interpolate', '$route', '$routeParams', '$location', function($interpolate, $route, $routeParams, $location) {

                // Create an interpolation function for the routes
                angular.forEach(namedRoutes, function(route, name) {
                    namedRoutes[name] = $interpolate(route);
                });

                // Update the route object with named routes
                $route.to = {};

                // For all the named routes, allow automatic param injection with override based on the existing context
                angular.forEach(namedRoutes, function(route, name) {
                    $route.to[name] = function(params) {
                        params = angular.extend({}, $routeParams, params);
                        $location.path(route(params));
                    };
                });

                // We just return the original route service
                return $route;
            }];
        }])
        .run(['$namedRoute', function() {
            // inject $namedRoute into $route
        }]);

}(this.angular));