
Existing member? Log in and continue learning

See if you like it, start the course for free!

Unlock full course by purchasing a membership
Understanding Dependency Injection in Angular
Understanding Dependency Injection in Angular
Dependency injection is another concept that is not unique to Angular, it is a general programming pattern. In the context of Angular, the idea is that instead of creating instances of classes ourselves, e.g:
export class AppComponent { myService = new MyService();}
Angular will handle creating new
instances of our classes, and provide them to
us through dependency injection which looks like this:
export class AppComponent { constructor(private myService: MyService){}}
or this:
export class AppComponent { private myService = inject(MyService);}
Angular will use the MyService
type here as an InjectionToken
. This is how
Angular knows we want an instance of MyService
. The instance of MyService
is
assigned to myService
and then we can use it. By using the private
or
public
keyword, this will make myService
available as a class member to the
entire class, rather than just being available within the constructor
.
Technically, the private
keyword is only required for the inject
syntax if
you want the class member to specifically be private
.
In both of the examples above, we now have an instance of MyService
that is
available on this.myService
throughout the class.
Why Dependency Injection?
Why do this in Angular? Why not just create new instances ourselves? Some benefits are:
- It makes automated testing easier as we can easily provide fake versions of dependencies instead of real ones (automated testing is a bit more advanced and not something we actually cover in this course)
- It allows us to share instances of our objects more easily. This way we can have two separate components share the same single instance of a service, which means they will be able to share data, or we could create two separate instances of the service if we prefer.
- It makes creating instances much easier, as we don’t need to pass all of the dependencies that the service itself depends on.
That last one is a bit less clear, so let’s expand on that. Imagine that
MyService
also has two dependencies of its own that it needs injected:
export class MyService { constructor(http: HttpClient, someOtherService: SomeOtherService){}}
To do its job, MyService
also needs an instance of HttpClient
and
SomeOtherService
. If we are using Angular’s dependency injection system
then we can just do this to inject MyService
somewhere else in our app:
export class AppComponent { constructor(private myService: MyService){}}
But if we are not using dependency injection, then we need to pass all of
the MyService
dependencies manually like this:
export class AppComponent { myService = new MyService(new HttpClient(), new SomeOtherService())}
Imagine doing this several times throughout your application, and then we need
to update MyService
to have a third dependency:
export class MyService { constructor(http: HttpClient, someOtherService: SomeOtherService, anotherService: AnotherService){}}
Now we would need to go back and update every instance of MyService
we are
creating:
export class AppComponent { myService = new MyService(new HttpClient(), new SomeOtherService(), new AnotherService())}
Perhaps you can see how this would become a massive pain.
Understanding Tokens and Providers
We have already seen how dependency injection works:
export class AppComponent { constructor(private myService: MyService){}}
It seems we just add a parameter to the constructor
, and give that parameter
a type of whatever we want Angular to inject for us. Give it a type of
MyService
and we will get an instance of MyService
.
This is an accurate enough understanding, but let’s dive a little bit deeper.
What we are doing here is supplying a type token (we can also use string
tokens but this is not as common). You might think that Angular knows what
MyService
is because we would import that at the top of our file:
import { MyService } from './shared/data-access/my-service';
// ...snip
export class AppComponent { constructor(private myService: MyService){}}
It seems sensible to think that Angular will just go find MyService
from that
file and create a new instance of it, but that isn’t exactly how it works. This
type is being used as a token and what that token represents depends on
how it is provided.
Providing Tokens
One aspect of components and modules that we have not looked at yet is the
providers
array, and this is relevant to how tokens are provided. First of
all, manually providing tokens is not nearly as common as just doing this:
@Injectable({ providedIn: 'root'})export class MyService {}
Thanks for checking out the preview of this lesson!
You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).