App.settings - Angular way?

2022-08-30 04:52:11

我想在我的应用程序中添加一个部分,它将包含一些const和预定义的值。App Settings

我已经阅读了这个答案,它使用但它在Angular中被弃用。本文解释了这些差异,但它没有提供完整的示例,我的尝试也没有成功。OpaqueToken

以下是我尝试过的(我不知道这是否是正确的方法):

//ServiceAppSettings.ts

import {InjectionToken, OpaqueToken} from "@angular/core";

const CONFIG = {
  apiUrl: 'http://my.api.com',
  theme: 'suicid-squad',
  title: 'My awesome app'
};
const FEATURE_ENABLED = true;
const API_URL = new InjectionToken<string>('apiUrl');

这就是我想使用这些consts的组件:

//MainPage.ts

import {...} from '@angular/core'
import {ServiceTest} from "./ServiceTest"

@Component({
  selector: 'my-app',
  template: `
   <span>Hi</span>
  ` ,  providers: [
    {
      provide: ServiceTest,
      useFactory: ( apiUrl) => {
        // create data service
      },
      deps: [

        new Inject(API_URL)
      ]
    }
  ]
})
export class MainPage {


}

但它不起作用,我得到错误。

问题:

如何以Angular方式使用“app.settings”值?

plunker

注意 当然,我可以创建可注射服务并将其放入NgModule的提供者中,但是正如我所说,我想用,Angular的方式做到这一点。InjectionToken


答案 1

如果您使用的是 ,还有另一种选择:

Angular CLI 在 中提供环境文件(默认为 (dev) 和 (production))。src/environmentsenvironment.tsenvironment.prod.ts

请注意,您需要在所有文件中提供配置参数,例如:environment.*

环境:ts

export const environment = {
  production: false,
  apiEndpoint: 'http://localhost:8000/api/v1'
};

environment.prod.ts

export const environment = {
  production: true,
  apiEndpoint: '__your_production_server__'
};

并在服务中使用它们(自动选择正确的环境文件):

api.service.ts

// ... other imports
import { environment } from '../../environments/environment';

@Injectable()
export class ApiService {     

  public apiRequest(): Observable<MyObject[]> {
    const path = environment.apiEndpoint + `/objects`;
    // ...
  }

// ...
}

Github(Angular CLI 版本 6)官方 Angular 指南(版本 7)中阅读有关应用程序环境的更多信息。


答案 2

不建议将这些文件用于 API URL 配置。看起来你应该这样做,因为这提到了“环境”这个词。environment.*.ts

使用这个实际上是编译时配置。如果要更改 API URL,则需要重新构建。这是你不想做的事情...只需询问您友好的QA部门:)

您需要的是运行时配置,即应用程序在启动时加载其配置。

其他一些答案也涉及这一点,但不同之处在于,配置需要在应用程序启动后立即加载,以便正常服务可以在需要时使用它。

实现运行时配置:

  1. 将 JSON 配置文件添加到文件夹(以便在生成时复制该文件)/src/assets/
  2. 创建一个以加载和分发配置AppConfigService
  3. 使用APP_INITIALIZER

1. 将配置文件添加到/src/assets

您可以将其添加到另一个文件夹,但您需要通过更新配置文件来告诉Angular CLI它是一个资产。从使用资产文件夹开始:angular.json

{
  "apiBaseUrl": "https://development.local/apiUrl"
}

2. 创建AppConfigService

这是每当您需要配置值时将注入的服务:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class AppConfigService {

  private appConfig: any;

  constructor(private http: HttpClient) { }

  loadAppConfig() {
    return this.http.get('/assets/config.json')
      .toPromise()
      .then(data => {
        this.appConfig = data;
      });
  }

  // This is an example property ... you can make it however you want.
  get apiBaseUrl() {

    if (!this.appConfig) {
      throw Error('Config file not loaded!');
    }

    return this.appConfig.apiBaseUrl;
  }
}

3. 使用APP_INITIALIZER

为了在配置完全加载的情况下安全地注入,我们需要在应用启动时加载配置。重要的是,初始化工厂函数需要返回 a,以便 Angular 知道等到它完成解析后再完成启动:AppConfigServicePromise

import { APP_INITIALIZER } from '@angular/core';
import { AppConfigService } from './services/app-config.service';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [
    {
      provide: APP_INITIALIZER,
      multi: true,
      deps: [AppConfigService],
      useFactory: (appConfigService: AppConfigService) => {
        return () => {
          //Make sure to return a promise!
          return appConfigService.loadAppConfig();
        };
      }
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

现在,您可以将其注入到任何需要的地方,并且所有配置都将准备好读取:

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {

  apiBaseUrl: string;

  constructor(private appConfigService: AppConfigService) {}

  ngOnInit(): void {
    this.apiBaseUrl = this.appConfigService.apiBaseUrl;
  }

}

我不能说得足够强烈,将API URL配置为编译时配置是一种反模式。使用运行时配置。