Angular 2 Set APP_BASE_HREF with a value from a Promise / Observable

夙愿已清 提交于 2019-12-22 06:00:13

问题


I try to set the APP_BASE_HREF in the "CoreModule" with a value from a async rest call. I can't see how this is done, because the provide method needs to return a string.

for example:

@NgModule({
    imports: [
        ...
        HttpModule
    ],
    ...
    providers: [
        ...
        ...
        BackendRequestClass,
        { provide: APP_BASE_HREF, useFactory: () => () => return '/some/path', deps: [], multi: true }
    ],
});

but when I need the value from a webservice, I can't return the string. Any ideas how this could be done?

thx


回答1:


I tried your solution. The problem is, that at the time

{ provide: APP_BASE_HREF, useFactory: (config) => config.appBaseHref, deps: [ConfigService] }

the config.appBaseHref is not set yet. When I debug the code I see, that the APP_INITIALIZER is executed after the provider from APP_BASE_HREF

That causes, that the BASE_HREF is not set.




回答2:


We had the same challenge: Set the APP_BASE_HREF dynamically, based on a result from an async API call to allow routing of an app which can be accessed through different URLs.

While the solution presented by Günter looks sweet, it unfortunately did not work, at least with Angular 7. In our case, APP_BASE_HREF always took precedence over APP_INITIALIZER, so we couldn’t initialize the APP_BASE_HREF based on the resolved promise value returned from the initializer.

Instead, I implemented the API call to happen before the Angular bootstrapping and then injected the provider so that it’s available within the Angular context.

Adding to main.ts:

fetchConfig().then(config => {
  platformBrowserDynamic([ { provide: ConfigData, useValue: config } ])
    .bootstrapModule(AppModule)
    .catch(err => console.log(err));
});

We can then configure the APP_BASE_HREF in the providers within app.module.ts:

providers: [
  // …
  { 
    provide: APP_BASE_HREF, 
    useFactory: (config: ConfigData) => config.base, 
    deps: [ ConfigData ] 
  }
]

[edit 2019-08-21] Clarification per the comments: fetchConfig() is the API request which gets the configuration and returns a Promise. And ConfigData is not an Angular service, but just a simple class which gets instantiated in fetchConfig() and which gives me type safety when accessing it later in my application:

function fetchConfig (): Promise<ConfigData> {
  return fetch('/api/config')
    .then(response => response.json())
    .then(response => new ConfigData(response));
}



回答3:


You can use APP_INITIALIZER to get the path in advance and then use a dependency as shown in Angularjs2 - preload server configuration before the application starts

export function loadConfig(config: ConfigService) => () => config.load()

@NgModule({
    declarations: [AppComponent],
    imports: [BrowserModule,
        routes,
        FormsModule,
        HttpModule],
    providers: [
        ConfigService,
        BackendRequestClass,
        { provide: APP_INITIALIZER,
          useFactory: loadConfig,
          deps: [ConfigService], 
          multi: true },
        { provide: APP_BASE_HREF, useFactory: (config) => config.appBaseHref, deps: [ConfigService] }

    ],
    bootstrap: [AppComponent]
})
export class AppModule { }

The ConfigService can inject BackendRequestClass or Http and fetch the data and then make it available using its appBaseHref property (just an example how it could be done).



来源:https://stackoverflow.com/questions/46190280/angular-2-set-app-base-href-with-a-value-from-a-promise-observable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!