Configuring Angular Dependency Providers
Updated: 31 January 2024
Angular uses dependency injection for managing dependencies between different parts of your application. This works fairly well for your application code as you have full control over your dependencies. A problem comes up however when working with dependencies provided by some 3rd party code that we cannot easily control or manipulate the dependencies of
An example of this is as follows:
I have some service defined in some library code that requires a predefined dependency:
1class LibraryService {2 constructor(dep: PredefinedDependency) { }3}
Now, when configuring the library you are told to add PredefinedDependency
to your Angular providers list, like so:
1providers: [2 // other stuff3 PredefinedDependency4]
The PredefinedDependency
takes some inital configuration but in our application we have a usecase where something about our dependency may need to change at runtime, for example when a user logs in we may want to swap out the credentials used for the dependency. This would be fine if we were using the dependency directly, but since it is used in some library code we can’t change it at that level
Configuring our own Dependencu
What we can do instead is provide our own class that extends the one that the library requires:
1@Injectable()2class MyConfigurableDependency(){3 constructor(private dep: PredefinedDependency) {}4}
Then, we can provide this to Angular in place of the PredefinedDependency
type with useClass
:
1providers: [2 // other stuff3 {4 provide: PredefinedDependency,5 useClass: MyConfigurableDependency6 }7]
Usage
Since we have swapped out our dependency, we can modify the implementation of to do what we want:
1@Injectable()2class MyConfigurableDependency(){3 constructor(private dep: PredefinedDependency) {}4
5 getDataWithAuth(auth: string){6 // call some internal implementation for our usecase that we may want7 return this.internalStuff({8 auth9 })10 }11}
Or we can override the implementation used by the Library completely to work differently depending on some internal state that we can set elsewhere:
1@Injectable({2 // Provide as a singleton since we want to be able to modify the dependency's global state3 providedIn: 'root'4})5class MyConfigurableDependency(){6 useAuth = false7
8 constructor(private dep: PredefinedDependency) {}9
10 setAuthState(state: boolean) {11 this.useAuth = state12 }13
14 getDataWithAuth(auth: string){15 // call some internal implementation for our usecase that we may want16 return this.internalStuff({17 auth18 })19 }20
21 override getData(){22 if (this.useAuth) {23 return super.getData()24 } else {25 return this.getDataWithAuth()26 }27 }28}
… Or something like that depending on what you want to do, but that’s just normal OOP and less to do with Angular