loading...
Angular

That's why your Angular Interceptor may NOT WORK! πŸ˜₯ [5 seconds fix]

bartosz_io profile image Bartosz Pietrucha ・Updated on ・2 min read

EDIT: This problem does not occur when you import HttpClientModule only ONCE in the AppModule or CoreModule (and import the CoreModule into AppModule). Huge Kudos to @joekaiser for spotting the issue! πŸ™πŸ™πŸ™


It's time for another Angular Knowledge Pill!
It takes just a couple of seconds to learn something new πŸ”₯
Like taking your morning vitamins πŸ˜ƒ

πŸ‘‰ Angular creates a new Dependency Injector for a lazy-loaded module!

So what!? 🀐 For example, your HttpErrorInterceptor (or TokenInterceptor) may not work as you expect! Let's take a closer look. We have three modules CoreModule, AuthModule, and ExpensesModule. The first two modules are NOT lazy-loaded and register interceptors. The third, ExpensesModule is lazy-loaded and uses HttpClient to execute HTTP requests.

Alt Text
Alt Text
Alt Text

The solution πŸ‘‰ @SkipSelf()

Now, if we have ExpensesModule (lazy-loaded) and if we don't use @SkipSelf() when injecting HttpClient into a provider (here ExpenseApi), Angular will create a new instance WITHOUT previously registered HttpInterceptors - Error handling will not work! πŸ€¦β€β™‚οΈ Take a look at how to tell Angular not to create a new instance of a provider in the lazy-loaded module!

Alt Text

That's it! Problem is fixed! Your Interceptors are working properly πŸ’ͺ.


If you would like to receive this kind of knowledge pills directly into your mailbox, subscribe at angular-academy.com/blog/. I will be sending them regularly! Remember, it just takes 10 seconds to learn something new! πŸ˜ƒ

Discussion

pic
Editor guide
Collapse
joekaiser profile image
Joe

Does this still hold true if the expenses.module imports core.module?

Collapse
tieppt profile image
Tiep Phan

@joekaiser , I think the author was imported HttpClientModule to lazy-module, therefore it accidentally caused the creation of multiple instances. It was his fault.

stackblitz.com/edit/angular-mf67bq

Collapse
bartosz_io profile image
Bartosz Pietrucha Author

You should never import Core module into your feature modules, because it will create NEW instances of all providers. Core module should be imported only ONCE into App module (root module).

Collapse
joekaiser profile image
Joe

Well, that is going to be decided by what you in have in your core module. I guess in the example you gave, this is correct. But if you have a core module that for sharing common pipes and directives you do need to import it in sub modules. angular.io/guide/sharing-ngmodules

Let me back up a step. Are you saying the interceptor registered in your app.module won't load in the submodule without skipself?

Thread Thread
bartosz_io profile image
Bartosz Pietrucha Author

What I am saying is that "Angular creates a new Dependency Injector for a lazy-loaded module", what basicaly means that if this submodule is lazy-loaded, then yes.

But, don't take my words seriously, just give it a try in your code :)

Thread Thread
joekaiser profile image
Joe

OK, I must be missing the point or something. Take a look at this stack blitz stackblitz.com/edit/angular-hrwzgv

The interceptor is defined in the app.module, and the sub module is lazy loaded.

Click on the sub module link and check the console. The interceptor was run just fine.

What am I doing different?

Thread Thread
michaeljota profile image
Michael De Abreu

Nothing. I have never seen that problem before if you load CoreModule in AppModule once.

Thread Thread
bartosz_io profile image
Bartosz Pietrucha Author

Joe, first of all thank you for taking the time to dig deeper into this topic. I need to apologize you. You are 100% right. Since you have HttpClientModule imported at the root level (app module), all is fine. The problem I faced was caused by the fact, that I imported HttpClientModule the second time in the SharedModule... πŸ˜₯. This really confused me and I am sorry. Finally, I believe the best way is to import HttpClientModule once (in the AppModule or CoreModule).

Again, thanks! I will update the article. Best,
Bartosz

Thread Thread
joekaiser profile image
Joe

It's how we learn, friend! :)

Collapse
anduser96 profile image
Andrei Gatej

Hi!

I tried to reproduce the problem, but everything seems to be working fine even without the @SkipSelf() decorator.

StackBlitz

Did I miss something?

Collapse
joekaiser profile image
Joe

No, I think he was confused. Look at the docs for skipSelf. I read them as: if you have a dependency defined in the main module and submodule, it allows you to tell angular which one to use.

However, if a dependency is only in the app module, you don't need to sorry about it.

angular.io/api/core/SkipSelf

Collapse
bartosz_io profile image
Bartosz Pietrucha Author

Andrei, no! I was missing important point! Please take a look at my previous comment, where I gave an explanation. Forgive me for misleading you! πŸ˜₯ I will update the article!

Collapse
michaeljota profile image
Michael De Abreu

Just to notice that this is in the docs, in usage notes angular.io/api/common/http/HttpInt...