3

What I want to achieve

An encapsulated application (form editor) that I can use inside another angular application, but also in any web application.


Idea

The main modules/components could be implemented as angular library (main component as shadow dom), so I can add an 'angular elements' wrapper to build the webcomponent, but can also import the library itself as a npm package inside my existing angular application. So my angular application would not load the complete javascript package, but just the modules, that are not provided but the other application, to get a better performance and integration.


Problem

For each requests from the library, I want an http interceptor to login / add the jwt token to the request header. When I build the application with the angular elements wrapper (doing nothing but importing the library and building the webcomponent), everything is working fine. When I add it to the angular application, the interceptor is not working as expected, because the other application also has an interceptor. I want to encapsulate the libraries interceptor to the library only. So I thought I just have to import the HttpClientModule inside my library again and get my own instance of it, so the defined HTTP_INTERCEPTORS provider inside the same file knows when to get triggered. Unfortunatelly this idea is not working and both are interfering.

AppModule

  • imports:
    • HttpClientModule(1)
    • CustomLibraryModule
  • providers:
    • HTTP_INTERCEPTORS(1)

CustomLibraryModule

  • imports:
    • HttpClientModule(2)
  • providers:
    • HTTP_INTERCEPTORS(2)

In best case, I want to import CustomLibraryModule inside a lazy loaded child module of my application.


Question

Am I choosing the right tools for this situation? Do you know what I am doing wrong to get my encapsulated http interceptor?

NePheus
  • 133
  • 1
  • 11
  • you can't encapsulate an interceptor without lazy loading. This is a weird idea as I don't know under what use case would find a library useful across apps that adds a JWT to my requests, but you need to wrap the http service if you want to do it – bryan60 Sep 27 '19 at 14:25
  • @bryan60 I think you can encapsualte it. But I agree with you on your second point : why would you make HTTP requests for a form library ? If I see that in your source code, I will be reluctant to use it ... –  Sep 27 '19 at 14:29
  • @Maryannah check usage notes on interceptors: https://angular.io/api/common/http/HttpInterceptor The only way you can have an "encapsulated" interceptor is in a lazy loaded module... and this isn't an intended / supported use case, more an unintended side effect of lazy loading that may break in future releases. Otherwise new HttpClientModule imports will overwrite prior ones. – bryan60 Sep 27 '19 at 14:31
  • @bryan60 oh well, I've never seen that. Thank you for that information ! –  Sep 27 '19 at 14:32
  • The use case: This form editor is connected with a backend. You can add an item with the form but also edit an existing one. Each field is saved on blur. There are also loaded some theme data, because of a multi customer purpose. This form editor should be integrated as part of a dashboard, but should also be standalone as webcomponent, to run it independently on each system. – NePheus Sep 27 '19 at 14:50

2 Answers2

1

Right now you are mixing concerns by saying this independent form editor knows your backend requires a JWT. The web component should be unaware of your backend implementation.

If you have a specific backend that all instances of this component should be talking to, then you could export an interceptor for any Angular applications to use, or you could encapsulate the adding the JWT to the request directly in your code and not use the interceptor at all.

Also, if you are using this in an application outside of Angular, you will still need Angular to be on the page (see https://angular.io/guide/elements

observingstream
  • 466
  • 3
  • 8
1

After some research I found the reason, why the CustomLibraryModule did not use its own interceptor, but the interceptor of the main application. The library uses API classes, that are generated by nswag (.NET backend). Unfortunately The generated injectable classes were configured as singleton, so each class was decorated with

@Injectable({ providedIn: 'root' })

I changed this config and now they are decorated just with

@Injectable()

Additionally I added the API classes in the 'providers' section of my module. Now its constructors are called with the HttpClient reference of the lazy loaded module and the correct interceptor gets called.

Because of lack of understanding, I slowly moved to this part of my code. So in the end it was my own fault, but I am thankful for your help and clarifications.

NePheus
  • 133
  • 1
  • 11
  • 1
    This is awesome, it would be great to see how you did this. Like your source code for your interceptor and where it is brought in. – imnickvaughn Mar 31 '20 at 20:55