Vyhledávání na webu

typescript - tovární služba při spuštění Angularu se nikdy nespustí


Mám startupovou službu, kterou používám ve své aplikaci v Angularu. Tato služba se používá k volání mého REST API a poskytuje uživateli URL adresu.

Mám soubor startup.service.ts, soubor app.config.json a soubor web.config, který je uveden níže:

//startup.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { catchError, map } from 'rxjs/operators';
import { Observable, throwError as _throw } from 'rxjs';

export interface Configuration {
  api: string;
}

@Injectable()
export class StartupService {
  constructor(private httpClient: HttpClient) {}

  private _startupData: Configuration;

  load(): Observable<Configuration> {
    const data = this.httpClient.get<Configuration>('app.config.json').pipe(
      map(config => config),
      catchError((error: any) => _throw(error))
    );
    data.subscribe(d => {
      this._startupData = d;
    });
    return data;
  }

  get startupData(): Configuration {
    return this._startupData;
  }
}
//app.config.json
{
  "api": "http://localhost:64403/api/status"
}
//web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <staticContent>
      <remove fileExtension=".json" />
      <mimeMap fileExtension=".json" mimeType="application/json" />
    </staticContent>
    <rewrite>
      <rules>
        <rule name="Angular routes" stopProcessing="true">
          <match url=".*" />
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          </conditions>
          <action type="Rewrite" url="/home/" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Ve svém modulovém programu jsem přidal následující kód

//app.module.ts
export function startupServiceFactory(
  startupService: StartupService
): Function {
  return () => {
    startupService.load();
  };
}

const routes: Routes = [
  { path: '', component: HomeComponent, pathMatch: 'full' },
  { path: '**', component: NotFoundComponent, pathMatch: 'full' }
];

@NgModule({
  declarations: [AppComponent, HomeComponent, NotFoundComponent],
  imports: [
    BrowserModule,
    CommonModule,
    VehicleStatusModule,
    FormsModule,
    HttpClientModule,
    HttpModule,
    RouterModule.forRoot(routes),
    LeafletModule.forRoot(),
    StoreModule.forRoot(reducers),
    EffectsModule.forRoot(effects),
    StoreRouterConnectingModule
  ],
  providers: [
    StartupService,
    {
      // Provider for APP_INITIALIZER
      provide: APP_INITIALIZER,
      useFactory: startupServiceFactory,
      deps: [StartupService],
      multi: true
    },
    // router state composition
    { provide: RouterStateSerializer, useClass: CustomSerializer }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

A kdykoli spustím aplikaci, dostanu následující chybu,

TypeError: Nelze přečíst vlastnost 'api' z undefined

pocházející z mého souboru app.service.ts. Mělo by to vrátit řetězec: "http://localhost:64403/api/status"

//app.service.ts
@Injectable({ providedIn: 'root' })
export class VehicleService {

  private API_URL = this.startupService.startupData.fleetApi;

  constructor(
    private http: HttpClient,
    private messageService: MessageService,
    private startupService: StartupService
  ) {}

Věc, která mě ještě více mate, je, že to před pár dny fungovalo, ale poté, co jsem přidal svůj NGRX store, to přestalo fungovat a zobrazilo mi výše uvedenou chybu. Můj debugging mi říká, že továrna služby při spuštění není volána. Ví někdo, co tu dělám špatně? Prosím dejte mi vědět, jestli je něco, co chcete, abych upřesnil.

Odpověď č. 1

Bylo nebylo, tento stejný scénář jsem vyřešil pomocí APP_INITIALIZER

https://angular.io/api/core/APP_INITIALIZER

https://devblog.dymel.pl/2017/10/17/angular-preload/

Odpověď č. 2

jedním způsobem je změnit svůj API_URL na getter

private get API_URL () {
   return this.startupService.startupData.fleetApi;
}