11

I've been tinkering with AngularJS and I've built up a small collection of directives and services that I would like to package into a single JS file so that I can use them anywhere.

I have some website specific settings that my module will need for API calls and that sort of thing. I'm just wondering what the Angular way of making configurable modules is. Obviously I don't want to have to modify my reusable JS file for each website, as that kind of defeats the purpose of having it. Seeing as the values are going to remain the same for each website it seems like an awful lot of hassle to pass them in as an argument on each function call, and I'd rather stay away from global variables as much as possible.

I've searched a lot of questions for the answers I seek, and the closest pattern I've found so far is to have my reusable module be dependant on a not included module called "settings" or something and then define that module in the page's JS file, allowing the reusable module to pull the values from it. Here's an example to show what I mean.

This seems backwards to me. It's kind of like having a function pull values from global values instead of passing the values in as arguments.

Is this really the best way of doing this, or is there an alternative?

Joshua Walsh
  • 1,915
  • 5
  • 25
  • 50

1 Answers1

11

It sounds like you're looking for a provider.

You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications.

Here's a very basic example of a provider:

myMod.provider('greeting', function() {
  var text = 'Hello, ';

  this.setText = function(value) {
    text = value;
  };

  this.$get = function() {
    return function(name) {
      alert(text + name);
    };
  };
});

This creates a new service, just like you might with myMod.service or myMod.factory, but provides an additional API that is available at config time—namely, a setText method. You can get access to the provider in config blocks:

myMod.config(function(greetingProvider) {
  greetingProvider.setText("Howdy there, ");
});

Now, when we inject the greeting service, Angular will call the provider's $get method (injecting any services it asks for in its parameters) and gives you whatever it returns; in this case, $get returns a function that, when called with a name, will alert the name with whatever we've set with setText:

myMod.run(function(greeting) {
  greeting('Ford Prefect');
});

// Alerts: "Howdy there, Ford Prefect"

This is exactly how other providers, like $httpProvider and $routeProvider work.

For more information on providers and dependency injection in general, check out this SO question on dependency injection.

Community
  • 1
  • 1
Michelle Tilley
  • 157,729
  • 40
  • 374
  • 311
  • This sounds like exactly what I need. I appear to have completely forgotten how to do DI in Angular over the weekend, so I'll go brush up on that and report back from there. – Joshua Walsh May 12 '14 at 03:02
  • Hmmm, I'm having trouble getting this to work. I can't seem to get ahold of my provider through DI... http://plnkr.co/edit/7BXP3bEFDsVQHKmkUjcU – Joshua Walsh May 12 '14 at 03:25
  • 1
    @YM_Industries Your code is working fine, but your `$get` is returning `settings.password`, which is undefined. Did you mean to return `settings` instead? – Michelle Tilley May 12 '14 at 03:28
  • Ugh, I guess it's just one of those mornings. – Joshua Walsh May 12 '14 at 03:31
  • Okay, I think all my reusable stuff is working, but I'm still a little unsure on how to change the settings. I've updated the Plunker to match my progress: http://plnkr.co/edit/7BXP3bEFDsVQHKmkUjcU – Joshua Walsh May 12 '14 at 03:38
  • 1
    @YM_Industries I've updated `script.js` to demonstrate: http://plnkr.co/edit/L0SKCink67ZqK1hmYjoR?p=preview – Michelle Tilley May 12 '14 at 03:44
  • So just to be clear, AngularJS automatically makes settingsProvider out of settings? – Joshua Walsh May 12 '14 at 03:46
  • 1
    @YM_Industries Yes, because you declared it as a `provider`. (Technically, every single service, no matter how you create it, gets a provider, but only those created with `.provider` do anything of significance) – Michelle Tilley May 12 '14 at 03:49
  • Good to know! Thankyou so much for your help, I think I understand it enough now to carry on on my own. – Joshua Walsh May 12 '14 at 03:53
  • 1
    @YM_Industries No problem! Give me [a ping](http://brandontilley.com/contact.html) if you run into issues. – Michelle Tilley May 12 '14 at 03:53