I think the answers are right but I think something is missing.
The thing which is missing is "why and what it solves ?".
Ok let's start.
First let's mention some info:
All modules has access to the root services.
So even lazy loaded modules can use a service which was provided in app.module
.
What will happen if a lazy loaded module will provide to itself a service which the app module already provided ? there will be 2 instances.
It's not a problem but sometimes it is.
How can we solve it ? simply don't import a module with that provider to lazy loaded modules.
End of story.
This ^ was just to show that lazy loaded modules has their own injection point ( as opposed to non-lazy-loaded modules).
But what happens when a shared(!) module has declared providers
, and that module is imported by lazy and app.module
? Again, like we said, two instances.
So how can we solve this in the shared module POV ? We need a way not to use providers:[]
! Why? because they will be auto imported to both consuming lazy and app.module and we don't want that as we saw that each will have a different instance.
Well, it turns out that we can declare a shared module that won't have providers:[]
, but still, will provide providers ( sorry :))
How? Like this :
Notice, no providers.
But
Entering Manual mechanism via convention :
You will notice that the providers in the pictures have service1
and service2
This allows us to import service2
for lazy loaded modules and service1
for non-lazy modules. ( cough...router....cough)
BTW, no one is stopping you to call forRoot
within a lazy module. but you will have 2 instances because app.module
should also do it - so don't do it in lazy modules.
Also - if app.module
calls forRoot
(and no one calls forchild
) - that's fine, but root injector will only have service1
. ( available to all app)
So why do we need it? I'd say :
It allows a shared module , to be able to split its
different-providers to be used with eager modules and lazy modules -
via forRoot
and forChild
convention. I repeat : convention
That's it.
WAIT !! not a single word about singleton ?? so why do I read
singleton everywhere ?
Well - it's hidden in the sentence above ^
It allows a shared module, to be able to split its
different-providers to be used with eager modules and lazy modules -
via forRoot and forChild.
The convention (!!!) allows it to be singleton - or to be more precise - if you won't follow the convention - you will NOT get a singleton.
So if you only load forRoot
in the app.module
, then you get only one instance because you only should call forRoot
it in the app.module
.
BTW - at this point you can forget about forChild
. the lazy loaded module shouldn't / won't call forRoot
- so you're safe in POV of singleton.
forRoot and forChild are not one unbreakable package - it's just that there is no point of calling for Root which obviously will be loaded only in app.module
without giving the ability for lazy modules , have their own services , without creating new services-which-should-be-singleton.
This convention give you a nice ability called forChild
- to consume "services only for lazy loaded modules".
Here is a demo Root providers yields positive numbers , lazy loaded modules yields negative numbers.
RouterService
for a single Angular2 application.forRoot
will initialize that service and register it to DI together with some route config, whileforChild
will only register additional route configs and tell Angular2 to reuse theRouterService
thatforRoot
has created. – Harry Ninh