I think your problems would be solved if you would just expose the config as an Observable and "await" it where it's needed. How to share api response between multiple Angular Components? PS: I haven't added any code in here as I am not really confident if what I have tried is sensible or not, but happy to add some code. In the US, how do we make tax withholding less if we lost our job for a few months? But, the APP_INITIALIZER is a multi-provider service that is composed of functions that each return a Promise. So, if you have a Service that is used by a single component; and that component is never mounted; then, Angular will never instantiate that Service. Stackblitz1 (single APP_INITIALIZER) - https://stackblitz.com/edit/angular-puaw7a, [The Problem] Stackblitz2 (multiple APP_INITIALIZER) - https://stackblitz.com/edit/angular-7uqijv. For the sake of this demo, I'm going to use a simple app.config.json text file: The question then becomes, how do we grab that API Token; and, do it in such a way that makes it available for ************ dependency injection. That's the beauty of dependency-injection (DI) - it inverts the relationships. This works because nothing in the application is attempting to eagerly consume the GeocodeService. To see this in action, I've created an AppInitializer Service that both loads the remote data and acts as a conduit for the subsequent Factory functions: As you can see, the AppInitializer loads the remote configuration data and then stores it as a public property. It means that we don't actually have to configure all of the application Services at the same time. You just have a value that other services depend on. Extract 2D quad mesh from 3D hexahedral mesh. It's in this "block and defer" period that we can use Angular's HttpClient to make an AJAX (Asynchronous JavaScript and JSON) request to the server. Then, the AppInitializer is required as a dependency for our IP_INFO_API_KEY factory function. Is there a PRNG that visits every number exactly once, in a non-trivial bitspace, without repetition, without large memory usage, before it cycles? Have you run into this problem? This helps a lot. After all, if we look at our GeocodeService class, it doesn't know anything about APP_INITIALIZER. In order to keep the application portable, we don't want to compile the API Token into the Angular code. Things I've tried: If second part (being able to make an API request to the back-end) was not in the picture, then I managed to use angular APP_INITIALIZER to get things done, I then searched for some articles and found this one Managing dependencies among App Initializers in Angular, which has 3 approaches listed, 3rd one being the recommended one (as it is easy to maintain), but I don't really understand all of it, I believe author has not included full code implementation of each approach (I do get that it's authors call whether to provide code samples or not, and I might be wrong). Unfortunately it runs into a brick wall quick when the project uses NGRX as the effects are merged prior to the APP_INITIALIZER (https://github.com/ngrx/platform/issues/931). And, the beautiful part of this is that the GeocodeService remains blissfully unaware of where any of its configuration data came from. Making statements based on opinion; back them up with references or personal experience. I don't think you actually need an initializer in your case. Now, one thing that is awesome about Angular's dependency-injection algorithm is that services aren't created until they are actually required by the application. Why did the gate before Minas Tirith break so very easily? Connect and share knowledge within a single location that is structured and easy to search. Sorry, I am not sure. I am the co-founder and a principal engineer at InVision App, Inc the world's leading online whiteboard and productivity platform powering the future of work. Story: man purchases plantation on planet, finds 'unstoppable' infestation, uses science, electrolyses water for oxygen, 1970s-1980s, in cricket, is it a no-ball if the batsman advances down the wicket and meets fulltoss ball above his waist, Revelation 21:5 - Behold, I am making all things new?. I thought this was totally fascinating; and, I wanted to riff on it a bit more. The Angular application will "block and defer" bootstrapping until each APP_INITIALIZER Promise is resolved. I also haven't created too many applications where I have complex configuration requirements. The thing that's so fascinating about Dave's post is that he's using the APP_INITIALIZER to actually load remote configuration data from the server using an AJAX request. ( await service1.init(); await service2.init(); ), angular multiple APP_INITIALIZER that depend on each other, Managing dependencies among App Initializers in Angular, https://stackblitz.com/edit/angular-puaw7a, https://stackblitz.com/edit/angular-7uqijv, How APIs can take the pain out of legacy system headaches (Ep.
Run this demo in my JavaScript Demos project on GitHub. Using the AJAX request we can load configuration data that can be used to customize our application for a specific environment. As such, we probably want to use a "paid" API Token with a high rate-limit in production. Take, as a thought experiment, a simple Geolocation Service that leverages the IPInfo.io API: Each of these API calls needs to include an API Token. Announcing the Stacks Editor Beta release! That's the miracle of dependency-injection (DI) and inversion of control (IoC). In app-module define providers like this: AppConfig.instance$ is a Subject which emits value after config is loaded. Once we have our AppInitializer, we just need to pull the Providers into our application module: Now, if we run this Angular application, we can see that the remote configuration data is successfully loaded, allowing the application to be bootstrapped: As you can see, this worked quite nicely! In the past, I've looked at the APP_INITIALIZER as a means to re-create the "run blocks" that we knew in AngularJS. If want to do it with the APP_INITIALIZER just await the services init in order of the dependencies. I would really appreciate if anyone with experience could share their knowledge wrt the same. Now that Dave has demonstrated how to load the configuration data, I wanted to take a closer look at how you might then use that configuration data to actually configure the Angular application. For use of code, Dave Bush discusses his blog post about storing Angular configuration data, APP_INITIALIZER as a means to re-create the "run blocks", NgModule constructors could provide an even more straight-forward "run block", Loading And Using Remote Feature Flags In Angular 9.0.0-next.12, Providing Module Configuration Using forRoot() And Ahead-Of-Time Compiling In Angular 7.2.0, Using Embedded Data To Provide Request-Specific Application Configuration In Angular 7.2.0, NgModule Constructors Provide A Module-Level Run Block In Angular 2.1.1, Providing Run Blocks As Services That Implement A Runnable Interface In Angular 2.1.1, Providing Run Blocks Using A Service Constructor In Angular 2.1.1, Configuring A Service With Both Dependency-Injection And A Run Block In Angular 2.1.1, Handling Service Configuration Without A Configuration Phase In Angular 2.1.1, Creating A "Run Block" In AngularJS 2 Beta 8, My Experience With AngularJS - The Super-heroic JavaScript MVW Framework, https://github.com/ngrx/platform/issues/931. Site design / logo 2022 Stack Exchange Inc; user contributions licensed under CC BY-SA. Thanks @eliseo, I lost 3+ hours just because I don't know how to do a proper search. On the latest Adventures In Angular podcast, Dave Bush discusses his blog post about storing Angular configuration data outside of the compiled application files. And, that API Token is tied to a particular rate-limit. I know that it's been while, but I have yet another solution. For example, we probably want to use different API keys in Production and in Development. This linked approach requires some server-side processing so that it can serialize and embed page-specific configuration data in the page that is serving up the Single-Page Application (SPA). Goal: be able to initialize two services using APP_INITIALIZER (say A & B), where B has a dependency on A. check out this stackblitz to see the problem. Where developers & technologists share private knowledge with coworkers, Reach developers & technologists worldwide, Thanks Eliseo, this does the trick for my scenario. Trending is based off of the highest score sort and falls back to it if no posts are trending. Background: I need to perform couple of initial checks during the application start up (1) read angular app config from ./assets/config.json file and get the API end point from there, (2) make an API call to end point retrieved in first step and load some settings from back end. Angular app, Angular Route Resolver executing multiple times with rapid clicking. Well, the flexibility of Observables is that you can can do what ever you want so you can also start loading config as soon as the service is constructed.
So, we can use the APP_INITIALIZER to load the remote data. And, if any of the Promises are rejected, the Angular application won't be initialized at all. For the app to fail to load, the bast place is an HTTP_INTERCEPTOR, or even a route guard. Time between connecting flights in Norway, Scientific writing: attributing actions to inanimate objects. What purpose are these openings on the roof? That said, if you are already in that kind of a context, embedded the configuration data can make life a bit more simple. In his post, Dave uses the APP_INITIALIZER multi-provider to load remote configuration data using an AJAX request as part of the application bootstrapping process. Want to use code from this post? Instead, we want to pull the API Token from an external source. To learn more, see our tips on writing great answers. And, part of makes Angular such a powerful framework. Why is rapid expansion/compression reversible? I haven't really used NgRX much (I'm still very much a noob when it comes to externalized state management). What would the ancient Romans have called Hercules' Club? The benefits are that the application loads as much as it can until the config requests are done. View this code in my JavaScript Demos project on GitHub. I still curious if it'd be possible to implement something similar to. Deep thoughts by @BenNadel - Defining Dynamic AJAX-Driven Service Providers Using APP_INITIALIZER In Angular 6.1.4, Ben Nadel 2022. I see the use of APP_INITIALIZER being recommended for runtime config of an Angular app, almost exclusively. I soon discovered, however, that the NgModule constructors could provide an even more straight-forward "run block". This "lazy evaluation" is going to be a key ingredient in our remote configuration integration. Check out the license. It is inside this factory function that we then translate the remote configuration data into a local dependency-injection Provider for our GeocodeService. If so, what methods have you used to get around the issue and still have runtime config? Or just transform it via observable piping and expose it further as an observable to defer everything until it's actually needed. You can now choose to sort by Trending, which boosts votes that have happened recently, helping to surface more up-to-date answers. By separating the application logic from the configuration data, it makes your compiled application portable across your various environments. Thanks for contributing an answer to Stack Overflow! By clicking Accept all cookies, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy. All content is the property of Ben Nadel. To subscribe to this RSS feed, copy and paste this URL into your RSS reader. Can a timeseries with a clear trend be considered stationary? As a quick follow-up to this post, here's another approach to configuring an Angular application using an embedded JSON payload: www.bennadel.com/blog/3561-using-embedded-data-to-provide-request-specific-application-configuration-in-angular-7-2-0.htm. By clicking Post Your Answer, you agree to our terms of service, privacy policy and cookie policy. Instead, we can use Factory functions to defer configuration until just before a given Service is instantiated. For example the shareReplay(1) operator will keep in memory the item and will defer the HTTP request until it's actually needed: Now your 2nd service can await the configData from the 1st service. This should be in the official documentation. In the twin paradox or twins paradox what do the clocks of the twin and the distant star he visits show when he's at the star? It just requires the API Token as part of its constructor. 465), Design patterns for asynchronous API communication. But, in the local development environment(s), we can use a "free" API Token that has a smaller rate-limit. I also rock out in JavaScript and ColdFusion 24x7 and I dream about chained Promises resolving asynchronously. Then, once the remote data is loaded - and the application bootstrapping is allowed to complete - we can consume the configuration data within subsequent Factory functions in order to configure the dependency-injection tokens for our configurable services (like the GeocodeService). I made wrapper for initializer function that depends on config. So, much of this is trial-and-error as I come up against issues. The GeocodeService doesn't have to care about where the configuration data is coming from - it leaves that decision making up to the DI container. As such, it won't get instantiated until after the APP_INITIALIZER runs and the IP_INFO_API_KEY has been configured. Asking for help, clarification, or responding to other answers. The problem in your code is that you have an async value and try to expose it as a sync value. Angular 2 APP_INITIALIZER Execution order / async issue, unable to validate multiple inputs using angular, Angular 5: APP_INITIALIZER runs on every route, Angular APP_INITIALIZER not delaying bootstrapping on success, Access each instance of reactive form inside ngfor in Angular, Angular imported modules do not wait for APP_INITIALIZER, How to show data from multiple checkbox in Array? I'm not going to get into the mechanics of the APP_INITIALIZER very much, since I think Dave's post covered it quite nicely. Find centralized, trusted content and collaborate around the technologies you use most. rev2022.7.21.42639. But, in both cases, I was only using the "run block" to manipulate services that had already been instantiated.