Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inject a config in AngularJS

Tags:

angularjs

I have a config that I'd like to be able to inject into Angular services, directives, etc. What is the best way to go about doing this?

I was playing with the idea of making config module:

'use strict';
angular.module('config', [])

But I wasn't sure how to construct the object literal that would be the actual config object that gets injected:

angular.module('myModule', ['ngResource', 'config'])
  .factory('myservice', function ($resource) {
        return $resource(config.myservice,{}, {
          // whatever
        })
  });

Would it be okay to just expose config as a service and inject that?

like image 218
binarygiant Avatar asked Aug 03 '13 19:08

binarygiant


2 Answers

I would say, the strategy varies, depending on what sort of config you have, but you have several options:

Module wide constants

If you only need several constants, you can use .value(), like this:

var app;

app = angular.module("my.angular.module", []);

app.value("baseUrl", "http://myrestservice.com/api/v1");

//injecting the value
app.controller("MyCtrl", ['baseUrl', function (baseUrl) {
  console.log(baseUrl); // => "http://myrestservice.com/api/v1"
}]);

See a more detailed answer here.

Fetching the config/config service

What i personally like to do is fetch my configuration from somewhere else via a service just as normal. It doesn't matter, if this is a remote location or just static information.

var app;

app = angular.module("my.angular.config", []);

app.service('Configuration', [function() {
  return {
    getbaseUrl: function() { return "http://myrestservice.com/api/v1" },
    getConfig: function() {
      return {
        answer: 42,
        question: "??"
      }
    }
  }
}]):

EDIT: example with an external fetch:

var app;

app = angular.module('my.module.config', []);

app.factory('ConfigurationData', ['$http', '$q', function(http, q) {
  var deferredConfig = q.defer();

  //error handling ommited
  http.get('http://remote.local/config.json').success(function(data) {
    return deferredConfig.resolve(data);
  });

  return {
    getConfig: function() {
      return deferredConfig.promise;
    }
  };
}]);

With this service, you can inject your config into other services, however, you can run into timing issues, as you have to inject and resolve the promise given by the service before anything you want to do with the config:

var app;

app = angular.module("my.other.module", ['my.module.config']);

app.factory('MyAwesomeService', ['ConfigurationData', function(config) {
  config.getConfig().then(function(config) {
    //do something with your config.
  });
}]);

You get a bit more fine control here, as you can react to different inputs. Again, it depends on your use case. You can use a factory here if you need additional logic for structuring the configuration.

Lastly, if you want even more control over configuration, you can make a

Custom Provider

Providers can be pretty useful, but i think they are a bit harder to design. Considering a baseUrl from the configuration needed for your app to work, you could write a provider for the service needing the value of the baseUrl like this:

var app;

app = angular.module('my.angular.module', []);

app.provider("RestServiceProvider", function(){

  this.baseUrl = 'http://restservice.com';

  this.$get = function() {
    var baseUrl = this.baseUrl;
    return {
        getBaseUrl: function() { return this.baseUrl; }
    }
  };

  this.setBaseUrl = function(url) {
    this.baseUrl = url;
  };
});

This lets you do cool stuff in the config phase of your application:

app.config(['RestserviceProvider', function(restServiceProvider) {

  restServiceProvider.setBaseUrl('http://wwww.myotherrestservice.com');

}]);

Every instance you fetch in a service/controller/etc. of RestService will now have the baseUrl set from the config phase from the moment you inject it.

For a more detailed overview, i suggest this gist.

like image 94
Florian Avatar answered Nov 15 '22 09:11

Florian


Creating a stand-alone module that only has a service or a directive (or both) is a great way to make application-independent angular code. If you do this you can easily just take that .js file and plop it into any project, and all you need to do is inject it into your applications and it just works.

So doing something like:

angular.module('config', [])
    .factory('config', function() {
        return {
            theme : 'nighttime',
            cursor : 'sword',
            ...
        };
    });

Then you can just inject it into any application like so:

angular.module('myModule', ['config'])
    .factory('myservice', function (config) {
        var theme = config.theme;
        var cursor = config.cursor;
        // do stuff with night-time swords!
    });

This is actually how the angular-ui team package all their directives, each directive is contained within its own module, which makes it easy for others to just take that code and reuse it in all their apps.

like image 33
Andrew Ho Avatar answered Nov 15 '22 09:11

Andrew Ho