Angular Dependency Injection – Understanding hierarchical injectors (2021)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hello guys! My name is Dmytro Mezhenskyi and let's talk today about Angular dependency injection. initially i was preparing a video about resolution modifiers like @Host, @Self() @SkipSelf() and so on, which i mentioned in my previous video "Top 5 Angular interview questions" but I have quickly realized that it is quite hard to explain this without knowing how the dependency injection mechanism works in angular and the second problem is that this topic "dependency injection in angular" is just too big to be able to briefly explain it in 3-5 minutes. So I decided to create a separate video where i will explain the dependency injection mechanism and in next videos we will already talk more about resolution modifiers and another dependency injection features. So stay here, subscribe and we are getting started... Alright, dependency injection what is that? So angular docs says dependency injection is a coding pattern in which class asks for dependencies from external sources rather than creating them itself. Well... good to know but first - why do we need it? well, the main reason of dependency injection is to avoid the hard dependencies between classes and the decoupling of object creation from using of this object enables you to replace dependencies without changing the class which is using them. Okay, what does it mean for us? well i'm pretty sure that every one of you knows how to create and inject services so we have a service called user services example which we inject in some component and what happens then? kind of magic right? But actually happens quite a straightforward thing - our component class doesn't create the instance of user service by itself but it delegates creating of the service instance to another guy called "Injector". So what is injector? Injector is an object in Angular dependency injection who is responsible for creating of the objects. if to simplify it as much as possible injector will create an instance of our dependency (UserService in our case) and provide it as a constructor parameter for our component in fact we can even code some simplified prototype of dependency injection in order to show you that there is no magic behind it. I will just go to my vs code and create a scratch file here let's create our service class... it is going to be user service which has some method... let's say... sayHi() and this method will just console log the string "Hi" and then let's create some i don't know component class which has a dependency on our user service and it should be passed via constructor all right so we just dropped the whole disk complexity annotation templates whatever and leave just classes but the idea is the same actually so now here below we gonna implement our dependency injection mechanism so let's create first a class of our injector cool then we know that in angular services are actually single tones in scope of injector and it means that we have to have some container where we will be storing our service instances right so if some component requests the instance of some service we just return the existing one instead of create the new instance of this service so i will introduce a private property called container which is going to be the instance of the map and if you don't know what is map it is very similar to plane object but it has 2k differences and the first one it guarantees the order of keys and the second one is that the key can be literally anything it can be even boolean or object and exactly this feature we will be using here so let's move forward then we need a method which will be kind of uh resolver of our dependencies so let's create a method uh i will call it get and this method takes one parameter which i'm gonna call service which is which has type any which makes sense because i can have really any service and then i just get the instance of our service using the service name as a key and return it but what we have to do in case if there is no instance for this service well uh let's throw an error in this case for now the next problem now is that we will be always getting an error right because our container is always empty for now so let's fix it i will create a constructor which will be taking one parameter called providers which is going to be array of services we going to provide and here in constructor we go through the array and create instances of these services and add each of them to our container and the key of the instance will be the service class name all right so looks good our resolver is ready so let's have a look how it would be used in the application when angular starts it creates an instance of injector and path all services which should be registered as a constructor parameter in our case we provide it manually but in angular it happens when we use providers property in our ng model component and directive annotation or if we configure it via provided in property inside injectable annotation then when angular creates an instance of our component it does something like this we use our injector in order to get an instance of our user service from dependency injection container and after this we can already get access to the instance of our user service and we can call its method say hi and as you can see it works fine right now if we remove a user service from provider array we get an error that says that no provider found and exactly this happens in angular when we forget to provide some service but then try to inject this in some component class of course this everything is hidden from you and this magic happens during the compilation time but once angular compiled the application you will see something similar to what we have right now not exactly this but similar alright good so i hope now you have a clear picture about how this dependency injection mechanism works and let's move forward and talk a little bit about injectors hierarchy yes angular has not only one injector but it creates a hierarchy of injectors and more of it there to here are his model injector and element injector hierarchy let's start with model injector when angular starts it creates a root injector where we'll be registered our services which we provided via injectable annotation and all services provided in ng model property called providers if those modules are not lazy loaded angular recursively goes through all models which are being used in the application and creates instances for provided services in root injector so if you thought that if you provide some service in some model and it will be available only in scope of this model it is actually wrong if you provide some service in eagerly loaded model it will be added to the root injector which makes it available across whole application but this root injector is not actually the highest in this hierarchy during application bootstrapping angular creates few more injectors above the root injector goes platform injector this one is being created by platform browser dynamic function inside main.ts file and it provides some platform specific features like i don't know dom sanitizer platform id token and so on and then at the very top there is a null injector the responsibility of this injector is very easy it just throws the error if something tries to find dependencies there but let's get back to our root model injector what about the child injectors for it we know that another models which we import in our root or app model they are not creating new child injectors and providers from them go to the root injector but it is valid only for non-lazy models but modules which were loaded lazily create its own injector which are children for our root injector and few years ago it could be a problem if you wanted to have a singleton service across whole app because this child injector would create a new service instance so you would have multiple instances of the same service today we usually don't have such a problem but sometimes you can still come across the for root pattern which was the way how to solve this issue okay cool so that was the model injector hierarchy now let's talk about element injector one element injector is being created for any tag that matches angular component or any tag on which directive is applied and you can configure it in component and directive annotations inside provider's property and it creates its own hierarchy likewise component one. Okay so... 2 hierarchies... now the question is how does angular resolve dependencies? what happens when some component declares dependency in its constructor? let's imagine that we have the next component structure and this will be also element injector hierarchy because we know that element injector is being created for every component or directive then we have a model injector hierarchy which is represented by our null injector platform injector and root injector and there will be no child injector let's keep it just simple for now we declare dependency in our grandchild component and provide a service in our root application component in this case angular starts traversing of element injector hierarchy first it checks if we have the service provided in this current component where the dependency declared if this component doesn't have it it will ask its parent and this one also has nothing then it goes up in the hierarchy and encounters our root component and root component says that yes i have this token you are looking for and our grandchild component will get the instance of the service from root component now let's imagine that we have the same case but we don't provide any service so now it looks like this at the beginning everything will be the same we go up through element injector hierarchy and encounter the root element injector root element injector says that hey man sorry i do not have what you're looking for and then angular goes back to the view where we started and checks in which model injector scope this component exists in our case it is the root model injector and it delegates resolving further to the model injector hierarchy starting from this model injector which our component belongs to and here happens the same scenario there is small hint though if this component was a part of lazy loaded component it would be a scope of child model injector so angular would start traversing the model injector tree from this child model injector and yeah if angular would find the provider in our root model injector it would inject this instance in our child grandchild component but in our case we have nothing provided so it will go up to the parent injector we'll try to resolve it there and if still nothing is found it will reach our null injector which throws the error and this is the very simplified representation of how angular dependency injection mechanism resolves dependencies okay guys that was it for today i hope you enjoyed this video and now you have better understanding of dependency injection mechanism in angular of course i'm going to cover more advanced and interesting topics regarding the angular dependency injection in my future videos so this is the right time to subscribe to my channel and of course don't forget to leave your feedback in comment section because it allows me to improve my content for you and make it more useful and more interesting so guys thank you for attention i wish you productive week take care and see you in the future
Info
Channel: Decoded Frontend
Views: 19,960
Rating: undefined out of 5
Keywords: angular hierarchical dependency injection, angular dependency injection explained, angular dependency injection in depth, angular dependency injection, angular dependency injection for dummies, angular dependency injection kudvenkat, angular dependency injection tutorial, angular dependency injection singleton, angular tutorial, web development, dependency injection, Programming
Id: G8zXugcYd7o
Channel Id: undefined
Length: 16min 30sec (990 seconds)
Published: Sun Sep 20 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.