5
\$\begingroup\$

I'd like to be able to define Angular constants in terms of other constants.

It's not possible to inject dependencies into Angular constant services. When I want one of my constants to depend on another of my constants, I use a provider service. This allows my constants to have dependencies (on other constants), but still be used in my .config method call.

This sets off my code smell for two reasons.

  1. I'm using a full-blown call to provider when I'm really just defining a constant. It's just that some constants are defined in terms of other constants, and I want to be able to use any of these constants in my .config call.

  2. I'm injecting providers into my .config call and then manually calling their $get methods. This seems to just be bypassing some of the tools Angular gives me. It seems to me if I'm calling $get in my own code, it may be a sign that I'm fighting the framework.

Here's some sample code that shows the above in action. It defines a constant service that's an enumeration type, then it defines another constant service that depends on the enumeration type, and last it calls the .config method, injecting the dependent constant service:

app.constant('authLevel', {
    Public: "Public",
    Admin: "Admin",
    SuperAdmin: "SuperAdmin"
});


app.provider("routes", function (authLevel) {

    var routes = [
        {
            path: "/",
            controller: "mapsController",
            templateUrl: "templates/mapsView.html",
            navBarLabel: "LEFT_NAV_BAR.MAPS_NAV_LABEL",
            navBarIconClass: "fa-map-marker",
            authLevels: [authLevel.Public, authLevel.Admin, authLevel.SuperAdmin],
        },
        {
            path: "/markers",
            controller: "markersController",
            templateUrl: "templates/markerListView.html",
            navBarLabel: "LEFT_NAV_BAR.TABLE_NAV_LABEL",
            navBarIconClass: "fa-table",
            authLevels: [authLevel.SuperAdmin],
        }
    ];

    this.$get = function () {
        return routes;
    };
});


app.config(function ($routeProvider, routesProvider) {

    var routes = routesProvider.$get();

    for (var i = 0; i < routes.length; i++) {
        var route = routes[i];
        $routeProvider.when(route.path, {
            controller: route.controller,
            templateUrl: route.templateUrl
        });
    }

    $routeProvider.otherwise({ redirectTo: "/" });
});

Am I right to have my code smell go off here?

Are there any sort of established patterns for defining Angular constants that use previously defined constants, and can still be used in the .config method?

\$\endgroup\$
6
\$\begingroup\$

Using an IIFE seems to be the tidiest way I've found to do it. This allows you to define your constant as a function (that is immediately invoked) that returns your constant object so you can use it as normal, i.e: LABELS.appName

.constant('LABELS', (function () {
    var self = {};
    self.appName = 'MyApp';
    self.companyName = 'MyCompany';
    self.appHeader = self.appName + ' | ' + self.companyName;
    return self;
})());//function is immediately invoked here

References:

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Welcome to Code Review! As far as I can tell, this is a pretty good first answer (it's even got a bibiography!) \$\endgroup\$ – Fund Monica's Lawsuit Dec 24 '15 at 15:34
  • \$\begingroup\$ IIFEs do let you control scope as you build complex objects. However, the constant I'm defining depends on a previously defined constant; I would still need a way to pass 'authLevel' into the anonymous function, something more like this: .constant('routes', (function (authLevel) {...})(?)); One might think I could say app.factory('routes', ['authLevel', function (authLevel) { ... }]), but dependencies defined using the factory method can't be used inside config. \$\endgroup\$ – jcarpenter2 Dec 25 '15 at 17:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.