I'd like to know if there is a way of making the configuration of a provider unique not across the entire application, but only across the module that is configuring it.
For example, I have a module "core" which contains the definition of a provider. Then I have modules "module1" and "module2" which use the provider but have to configure it in a particular way for the specific module.
What is happening with me is that the configuration done in the module defined last overrides the configuration done in all other modules that use the provider in the application.
I made this simple plunker to exemplify this:
var app = angular.module('app', ['module1','module2']);
angular.module('core',[])
.provider('movie', function () {
var version;
return {
setVersion: function (value) {
version = value;
},
$get: function () {
return {
title: 'The Matrix' + ' ' + version
}
}
}
});
angular.module('module1',['core'])
.config(function (movieProvider) {
movieProvider.setVersion('Reloaded');
})
.controller('ctrl1', function ($scope,movie) {
$scope.title = movie.title;
$scope.module = 'module1';
});
angular.module('module2',['core'])
.config(function (movieProvider) {
movieProvider.setVersion('Revolutions');
})
.controller('ctrl2', function ($scope,movie) {
$scope.title = movie.title;
$scope.module = 'module2';
});
In angular providers, $get is intended to return a single instance of the provided functionality; $get() is re-executed on each instantiation of the provider (like a factory). The function or object providing the definition of the provider is only instantiated once (like a service).
So, to get factory-like properties out of your provider you'd want to keep instance-specific properties scoped inside of $get; and to get service-like properties scoped outside of $get.
This may seem a bit limiting or roundabout at first, but it allows you to combine instance-scoped and globally-scoped properties in really nifty ways.
To your problem specifically, if we just move var version
into $get
, suddenly we get the factory-like behavior you were looking for:
.provider('movie', function () {
return {
$get: function () {
var version;
var obj = {
title: function() { return 'The Matrix' + ' ' + version; },
setVersion: function (value) {
version = value;
}
};
return obj;
}
}
});
(http://plnkr.co/edit/0m9qKzNuhCOOXTbrCQ1T?p=preview)
Changing the scope (along with changing title to be a function of a variable instead of a string generated statically at the creation of obj), gets us the desired output:
This is module module1
Title: The Matrix Reloaded
This is module module2
Title: The Matrix Revolutions
This is basically like a factory ATM.
To get into a more normal use case of a provider (where we want to combine global and per-instance scoping), let's say we wanted to have an API provider that uses may use one of several different APIs in different peoples' applications - but only one API per application. We'd want our provider to look roughly like this -
.provider('movie', function () {
var imdbEndpoint;
return {
setApiEndpoint: function(newImdbEndpoint) {
imdbEndpoint = newImdbEndpoint;
},
$get: function () {
var version;
var obj = {
title: function() { return imdbEndpoint + ' says the The Matrix version is ' + ' ' + version; },
setVersion: function (value) {
version = value;
}
};
return obj;
}
}
});
(http://plnkr.co/edit/ZoSgQDpNdX8MOmet7xzM?p=preview)
Output: This is module module1
Title: api.imdb.com says the The Matrix version is Reloaded
This is module module2
Title: api.imdb.com says the The Matrix version is Revolutions
So now our API endpoint URL is scoped globally (or on a per-application basis) but we can reference whichever movie we want without getting confused about which layer of the matrix Neo is in - because that's what this is really about, right?