I have an app-const.ts with a server URL:
export class AppConst {
public static serverPath = 'http://10.0.0.126:3031';
}
This is an URL path to Spring Boot REST server. At this case I hold this constant in one place and use it in all modules. However after a build I don't have a way to change this constant without re-building the whole project again if the server URL is changed.
Is there any way to hold this constant in some external configuration file on a hosting (next to index.html) so that I can change it without rebuilding the project (like application.properties file in Spring Boot, who knows)?
Or how I can easily manage the situation with changing server URL?
Addition. To clear situation: I place my Angular web-client on a hosting. Then this client starts communicate with a Spring Boot REST server that can be placed somewhere (in a cloud for example). This Spring Boot server has a server URL (serverPath) that might be changed sometimes. Now if server URL change I need to change this serverPath constant and rebuild the whole Angular project only due to this constant.
I have got a following solution. It uses external JSON configuration file.
So first create a JSON in assets/data folder.
config.json:
Then read and parse it.
config.service.ts:
Then you can save serverPath in LocalStorage in login component for example.
login.component.ts:
After that you can access serverPath in all your other services.
server.service.ts:
After a build you will see assets/data/config.json file in your dist folder. Copy all your dist folder to your hosting and all works.
Another solution would be to add it as a javascript variable in your index.html file. I used this method and it works.
Add it to the "head" part of your index.html with the "script" tags, example:
(my global variable is named "LMS_REST_API_URL")
After this you can access this variable like this:
I used it directly from the service that needs the URL, but it will probably also work in a seperate app-const.ts class file like you are using.
I used the assets folder to reference external configuration. The idea is that the deployment process updates the configuration for that environment into the assets folder which is then read on app startup. To do this, first place your configuration in
src/app/assets/config.json
. E.g.The deployment process can then update the
serverRoot
property within this file to the correct value for that environment, or replace the contents ofconfig.json
entirely.Then, create a model class in
src/app/model/environment.ts
which will allow type safe access to the configuration:Then, create a service to load the configuration in
src/app/services/environment-load.service.ts
:Finally, in your app module (
src/app/app.module.ts
), set theEnvironmentLoadService
as a Provider which is created during the app initialization stage of the app's lifecycle. This guarantees all promises are resolved before the app initialization stage is complete and that your config is fully loaded before the first component is constructed:I have several applications that do exactly this. I've built a utility library for my applications that includes this.
First, I have a "Configuration" class. The json configuration file gets loaded from the server and mapped to an instance of this class:
Then, there's the ConfigurationService, that is responsible for loading the configuration file:
As you can see, this service gets the configuration from a relative path, config/ui-config.json. The path is relative to the index.html file that was loaded to bootstrap the application. You need to arrange for the server to return the configuration file from that location.
The service will be hooked into Angular's initialization sequence (code to follow). It can be done either synchronously or asynchronously with respect to the app's initialization.
If you use the 'synchronous' method, then app initialization will pause while the json file is loaded. The upside to this is that once the app finishes initialization, the configuration is known to be available. The downside is the potentially long pause during initialization, where your user is looking at a blank page.
If you use the 'asynchronous' method, then the app initialization will only kick off the request for the config file, but will not pause to wait for that request to complete. Upside: quick (normal) initialization. Downside: you get an Observable of the Configuration instead of a Configuration, so you need to flatMap (mergeMap) over that Observable everywhere that you need the configuration.
Here's how it gets hooked into the app initialization, in app.module:
That's an example of the async config. For sync, just use
configurationServiceInitializerFactory
instead ofasyncConfigurationServiceInitializerFactory
Again, if you use the synchronous version, you can just inject the ConfigurationService into your services, and call it's
getConfig()
method.If you use the async version, you still inject the ConfigurationService into your services, but then you need to do something like this:
Edit: Oh, I almost forgot, I did a blog post on this a while back, and that has a little more detail. It's at https://chariotsolutions.com/blog/post/12-factor-ish-configuration-of-angular-applications/
And there's a complete example on GitHub at https://github.com/rfreedman/angular-configuration-service