Reputation: 5886
I'm creating a project where I need a "constants" class to contain some configuration values. Here is an extract of this class :
export class Constants
{
static Configuration = class
{
static CookieName:string = 'etl_language';
};
...
static View = class
{
static Militaries:string = 'militaries';
static Mutants:string = 'mutants';
static Objects:string = 'objects';
static Scientists:string = 'scientists';
};
}
When I'm in a component with Angular 2, I can use that class by importing it :
import {Constants} from "../../misc/constants";
And then, just reference it :
this.cookieName = Constants.Configuration.CookieName;
It works pretty well but I have the feeling that I should use the dependency injection engine of Angular 2 to inject a reference to that class in the constructor but it seems a bit overkill. However, I have the feeling that I'm violating the "Angular way" of doing things, so I don't know if I can stick with my solution or if I have to use DI.
Any advice ?
Upvotes: 16
Views: 23800
Reputation: 9652
My advice, for what it's worth. Don't ever use dependency injection unless you actually need it to solve a problem.
Use of DI where it isn't needed, or worse, systemic use of DI throughout an entire application just to satisfy some over-demanding framework will result in code that is incomprehensible. (Probably true of any design pattern).
Angular's hierarchical DI seems particularly egregious to me. Once your application gets large enough working out what is resolving a particular dependency and what else that instance is being shared with, will be a conundrum permeating your entire codebase.
Upvotes: 4
Reputation: 2280
What I might suggest doing instead is change your Constants
classes to have read-only properties and create a Providers[]
from them like so
@Injectable()
public class ConfigurationConstants() {
private _cookieName:string = 'etl_language';
...
get cookieName():string {
return this._cookieName;
}
...
}
export var CONSTANTS_PROVIDERS:Provider[] = [
provide(ConfigurationConstants, {useClass: ConfigurationConstants}),
provide(ViewConstants, {useClass: ViewConstatns})
];
Then you can bootstrap these providers into the top-level injector for your application making them available wherever you might need them.
import {CONSTANTS_PROVIDERS} from './constants';
bootstrap(App, [CONSTANTS_PROVIDERS])
.catch(err => console.error(err));
Here's a plunk to demonstrate: http://plnkr.co/edit/RPjDxoIZ8wLY3DDIdhJF
Edit 2: Plunker is back now and I've updated the example
Edit: Plunkr is dead right now so I can't update it but in my comment I meant something like this (I haven't tested this but it should work):
public class SubConstants() {
private _someString:string = 'Some String';
...
get someString():string {
return this._someString;
}
...
}
@Injectable()
public class ConfigurationConstants() {
private _cookieName:string = 'etl_language';
private _subConstants:SubConstants = new SubConstants();
...
get cookieName():string {
return this._cookieName;
}
get subConstants():SubConstants {
return this._subConstants;
}
...
}
// ... this would allow you to then do:
confConstants.subConstants.someString
// assuming you injected ConfigurationConstants as confConstants
Again this is more code than your suggestion of the inner classes so it's probably up to which you prefer.
Upvotes: 10
Reputation: 39268
DI is optional, but it's good for cases where you want to work with an instance of an object. Imports are ok in many cases, but DI decouples your code from the instantiation of the instance. This is beneficial if you are doing automated testing or want your component to be flexible and accept any object with a given signature.
I have some more info about DI here if you are interested: http://www.syntaxsuccess.com/viewarticle/dependency-injection-in-angular-2.0
Upvotes: 4