Reputation: 1037
I was creating a directive to display a chart. I went through the usual templates of creating a module, with a directive. For configuration, I decided to use a Provider. I understood how I could have the application set up my module's configuration through the provider.
However, one use case that I have is that the configuration can change based on the user's preferences at run-time. How do I enable my module to provide a way for the client API to modify the configuration at run-time?
Is it possible to inject the ProviderConfiguration into the Client's Controller as well? Are their any significant drawbacks to this approach?
The current code template looks like this
//Provider
angular.module('foobar', []).provider('foobarConfig', [function() {
var config = {
//config properties here.
}
var configurationProvider = {
//Getters and Setters that work on 'config'.
setProperty(prop, value) {
if(config[prop] !== undefined) {
config[prop] = value;
}
},
getProperty(prop) {
return config[prop];
},
$get: function() {
return this;
}
}
return configurationProvider;
}
//Chart Directive.
angular.module('foobar').directive('foobarChart', ['foobarConfig', function(foobarConfig) {
//Can use the foobarConfig here.
}]);
angular.module('clientApp', [ 'foobar'])
.config(['foobarConfigProvider', function(foobarConfigProvider) {
//Can provide the initial configuration to the module here.
foobarConfigProvider.setProperty("foo", "bar");
}]);
angular.module('clientApp').directive('clientFoo', function() {
//What should be done to change foobarConfig here?
});
Upvotes: 3
Views: 976
Reputation: 223308
Yes, it is perfectly valid recipe for configuration service which is available in both config and run phases, so foobarConfigProvider.setProperty("foo", "bar")
and foobarConfig.setProperty("foo", "bar")
can be used in the same way.
For the configuration service which doesn't have dependencies constant
is even more convenient alternative:
.constant('foobarConfig', (function () {
var config = {
// ...
};
return {
setProperty: function (prop, value) {
if(config[prop] !== undefined) {
config[prop] = value;
}
},
getProperty: function (prop) {
return config[prop];
}
};
})());
For ES5-compatible solution with limited set of configuration keys, constant
object with Object.defineProperty and Object.seal may be used, this eliminates the need for custom getter/setter functions. Object.defineProperty
may be iterated over initial config
object, so no boilerplate descriptor code is required:
.constant('foobarConfig', (function () {
var config = {
// ...
};
var obj = {};
angular.forEach(config, function (value, key) {
Object.defineProperty(obj, key, {
enumerable: true,
writable: true,
value: value
// no 'get' and 'set' are required if the only purpose for
// them is to restrict a set of config keys
})
});
Object.seal(obj);
return obj;
})());
Notice that the main difference (and possible drawback) for constant
here is that service value is being eagerly defined, foobarConfig
will be the same object for different injectors. Usually there is no difference for production, but this may (or may not) affect testing.
Upvotes: 1