Environment Variables in AngularJS and Ionic

I was reading my friend Josh Bavari's blog post on Managing Environment Variables for your Ionic Application where he describes his method for managing variables that change between enviroments (like connection strings and API endpoints). This got me thinking about how I have solved this problem in the past. Since Ionic makes use of Angular you get to apply all of your favorite Angular tips and tricks when you build an Ionic app. The method I'm going to describe can be used in any Angular app.

I like to create and Angular module that will hold these values and expose them as constants. I realize that calling something that is variable in nature a constant is weird but it refers to the way the variables will be exposed to my Angular application. Let's have a look:

First I'll create a module for my constants:

angular.module('coolapp-constants',[])  
  .constant('apiUrl', '@@apiUrl');

Don't worry about that @@apiUrl, I'll explain that in just a sec.

Next I'll add my constants as a dependecy on my main module:

angular.module('coolapp', ['coolapp-constants']);  

So now my API url can be injected into any services or controllers that need to make use of it like this:

angular.module('coolapp', ['coolapp-constants'])  
  .service('backendService', function($http, apiUrl){
      //Use the apiUrl variable to make API calls
  });

Cool! So we're gonna make requests to @@apiUrl? Nope! That is a variable substituion syntax used by a couple of Grunt and Gulp plugins, grunt-replace and gulp-replace-task, respectively. Before we can replace that @@apiUrl with the right value for a given environment we need to put the right values in some configuration files:

- config/
 ` localdev.json
 ` test.json
 ` production.json

Each file will have contents similar to:

// localdev.json
{
  "apiUrl":"https://dev.coolapp.com/api"
}

// production.json
{
  "apiUrl":"https://www.coolapp.com/api"
}

Great! Now we can use a Gulp or Grunt task to stuff the contents of the appropriate file into the constant in our module. I'll use Gulp here but you can use Grunt if you prefer:

var gulp    = require('gulp');  
var replace = require('gulp-replace-task');  
var args    = require('yargs').argv;  
var fs      = require('fs');

gulp.task('replace', function () {  
  // Get the environment from the command line
  var env = args.env || 'localdev';

  // Read the settings from the right file
  var filename = env + '.json';
  var settings = JSON.parse(fs.readFileSync('./config/' + filename, 'utf8'));

// Replace each placeholder with the correct value for the variable.  
gulp.src('js/coolapp-constants.js')  
  .pipe(replace({
    patterns: [
      {
        match: 'apiUrl',
        replacement: settings.apiUrl
      }
    ]
  }))
  .pipe(gulp.dest('build/js'));
});

Now I can call my Gulp task like so:

gulp replace --env production

So now my Gulp (or Grunt) task reads in the settings from the file that matches the environment name, replaces the values into the constants file, and then the constants are injected into any services or controllers that need them.

I really like using the Angular constants approach because it prevents my variable values from being assigned to "magic" global variables that my app depends on being defined. In this way they are injected where ever they are needed which will make the code very readable and testable in the same manner as all the rest of my Angular code.

Share this post:


My name is Jeff French. I'm a programmer, public speaker, technologist, husband, father and an all around geek. These are my musings on code, technology and life in general. Please enjoy. :)