Je veux ajouter une section App Settings
dans mon application où elle contiendra des const et des valeurs prédéfinies.
J'ai déjà lu cette réponse qui utilise OpaqueToken
mais il est déconseillé dans Angular. Cet article explique les différences, mais il ne fournit pas un exemple complet et mes tentatives échouent.
Voici ce que j'ai essayé (je ne sais pas si c'est la bonne façon):
//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');
Et voici le composant où je veux utiliser ces 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 {
}
Mais ça ne marche pas et j'ai des erreurs.
Question:
Comment utiliser les valeurs "app.settings" de la manière Angular?
NB Bien sûr, je peux créer un service Injectable et le mettre dans le fournisseur du NgModule, mais comme je l’ai dit, je veux le faire avec InjectionToken
, à la manière Angular.
J'ai compris comment faire cela avec InjectionTokens (voir exemple ci-dessous), et si votre projet a été construit avec le Angular CLI
, vous pouvez utiliser les fichiers d'environnement trouvés dans /environments
pour static application wide settings
comme un Point de terminaison de l'API, mais en fonction des exigences de votre projet, vous finirez probablement par utiliser les deux, car les fichiers d'environnement ne sont que des littéraux d'objet, tandis qu'une configuration injectable utilisant InjectionToken
peut utiliser les variables d'environnement et, comme c'est une classe, une logique peut être appliquée configurez-le en fonction d'autres facteurs de l'application, tels que les données de demande http initiales, le sous-domaine, etc.
Exemple de jetons d'injection
/ app/app-config.module.ts
import { NgModule, InjectionToken } from '@angular/core';
import { environment } from '../environments/environment';
export let APP_CONFIG = new InjectionToken<AppConfig>('app.config');
export class AppConfig {
apiEndpoint: string;
}
export const APP_DI_CONFIG: AppConfig = {
apiEndpoint: environment.apiEndpoint
};
@NgModule({
providers: [{
provide: APP_CONFIG,
useValue: APP_DI_CONFIG
}]
})
export class AppConfigModule { }
/ app/app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppConfigModule } from './app-config.module';
@NgModule({
declarations: [
// ...
],
imports: [
// ...
AppConfigModule
],
bootstrap: [AppComponent]
})
export class AppModule { }
Maintenant, vous pouvez simplement le DI dans n'importe quel composant, service, etc.:
/ app/core/auth.service.ts
import { Injectable, Inject } from '@angular/core';
import { Http, Response } from '@angular/http';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
import { APP_CONFIG, AppConfig } from '../app-config.module';
import { AuthHttp } from 'angular2-jwt';
@Injectable()
export class AuthService {
constructor(
private http: Http,
private router: Router,
private authHttp: AuthHttp,
@Inject(APP_CONFIG) private config: AppConfig
) { }
/**
* Logs a user into the application.
* @param payload
*/
public login(payload: { username: string, password: string }) {
return this.http
.post(`${this.config.apiEndpoint}/login`, payload)
.map((response: Response) => {
const token = response.json().token;
sessionStorage.setItem('token', token); // TODO: can this be done else where? interceptor
return this.handleResponse(response); // TODO: unset token shouldn't return the token to login
})
.catch(this.handleError);
}
// ...
}
Vous pouvez également taper vérifier la configuration à l'aide de la AppConfig exportée.
Si vous utilisez angular-cli , il existe une autre option:
La CLI angulaire fournit des fichiers d’environnement dans src/environments
(les valeurs par défaut sont environment.ts
(dev) et environment.prod.ts
(production)).
Notez que vous devez fournir les paramètres de configuration dans tous les fichiers environment.*
, par exemple,
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__'
};
et les utiliser dans votre service (le fichier d’environnement correct est choisi automatiquement):
api.service.ts
// ... other imports
import { environment } from '../../environments/environment';
@Injectable()
export class ApiService {
public apiRequest(): Observable<MyObject[]> {
const path = environment.apiEndpoint + `/objects`;
// ...
}
// ...
}
En savoir plus sur les environnements d’application sur Github (version 6 du CLI angulaire) ou dans le guide officiel Angular (version 7) .
Il est déconseillé d'utiliser les fichiers environment.*.ts
pour la configuration de votre adresse URL d'API. Il semble que vous devriez le faire car cela mentionne le mot "environnement".
Utiliser ceci est en fait configuration à la compilation. Si vous souhaitez modifier l'URL de l'API, vous devrez le reconstruire. C'est quelque chose que vous ne voulez pas avoir à faire ... il suffit de demander à votre département QA amical :)
Ce dont vous avez besoin, c’est configuration d’exécution, c’est-à-dire que l’application charge sa configuration au démarrage.
Quelques autres réponses abordent ce sujet, mais la différence est que la configuration doit être chargée dès le démarrage de l'application , de sorte qu'elle puisse être utilisée par un service normal quand il en a besoin.
Pour implémenter la configuration d'exécution:
/src/assets/
(copié lors de la construction)AppConfigService
pour charger et distribuer la configurationAPP_INITIALISER
/src/assets
Vous pouvez l'ajouter à un autre dossier, mais vous devez indiquer à la CLI qu'il s'agit d'un actif dans le angular.json
. Commencez par utiliser le dossier des actifs:
{
"apiBaseUrl": "https://development.local/apiUrl"
}
AppConfigService
C'est le service qui sera injecté chaque fois que vous aurez besoin de la valeur de configuration:
@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;
}
}
APP_INITIALISER
Pour permettre à la AppConfigService
d'être injectée en toute sécurité, avec la configuration entièrement chargée, nous devons charger la configuration au moment du démarrage de l'application. Il est important de noter que la fonction d’usine d’initialisation doit renvoyer un Promise
pour que Angular sache attendre la fin de la résolution avant la fin du démarrage:
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 { }
Maintenant, vous pouvez l’injecter où vous le souhaitez et toute la configuration sera prête à être lue:
@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;
}
}
Je ne saurais trop le dire, en configurant votre Les URL des API car la configuration à la compilation est un anti-motif. Utilisez la configuration d'exécution.
Voici ma solution, charge à partir de .json pour autoriser les modifications sans reconstruire
import { Injectable, Inject } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Location } from '@angular/common';
@Injectable()
export class ConfigService {
private config: any;
constructor(private location: Location, private http: Http) {
}
async apiUrl(): Promise<string> {
let conf = await this.getConfig();
return Promise.resolve(conf.apiUrl);
}
private async getConfig(): Promise<any> {
if (!this.config) {
this.config = (await this.http.get(this.location.prepareExternalUrl('/assets/config.json')).toPromise()).json();
}
return Promise.resolve(this.config);
}
}
et config.json
{
"apiUrl": "http://localhost:3000/api"
}
Voici mes deux solutions pour cela
1. Stocker dans des fichiers JSON
Créez simplement un fichier json et insérez votre composant dans la méthode $http.get()
. Si j’avais besoin de ce niveau très bas, c’est bon et rapide.
2. Stocker en utilisant des services de données
Si vous souhaitez stocker et utiliser tous les composants ou avoir une utilisation importante, il est préférable d'utiliser le service de données. Comme ça :
Créez simplement un dossier statique dans le dossier src/app
.
Créez un fichier nommé fuels.ts
dans un dossier statique. Vous pouvez également stocker d'autres fichiers statiques ici. Laissez définir vos données comme ceci. En supposant que vous ayez des données sur les carburants.
__
export const Fuels {
Fuel: [
{ "id": 1, "type": "A" },
{ "id": 2, "type": "B" },
{ "id": 3, "type": "C" },
{ "id": 4, "type": "D" },
];
}
__
import { Injectable } from "@angular/core";
import { Fuels } from "./static/fuels";
@Injectable()
export class StaticService {
constructor() { }
getFuelData(): Fuels[] {
return Fuels;
}
}`
importez simplement dans le fichier app.module.ts comme ceci et changez de fournisseur
import { StaticService } from './static.services';
providers: [StaticService]
Maintenant, utilisez ceci comme StaticService
dans n’importe quel module.
C'est tout.