vue que property cannot app javascript angular

javascript - que - App.settings: ¿la forma angular?



systemjs.config.js angular 6 (5)

Quiero agregar una sección de App Settings en mi aplicación donde contendrá algunos consts y valores predefinidos.

Ya leí esta respuesta que usa OpaqueToken pero está en desuso en Angular. Este article explica las diferencias, pero no proporcionó un ejemplo completo, y mis intentos no tuvieron éxito.

Esto es lo que he intentado (no sé si es la forma correcta):

//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'');

Y este es el componente donde quiero usar esos 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 { }

Pero no funciona y obtengo errores.

Pregunta:

¿Cómo puedo consumir los valores de "app.settings" de forma angular?

plunker

NB Claro que puedo crear un servicio inyectable y ponerlo en el proveedor del NgModule, pero como dije, quiero hacerlo con InjectionToken , de forma angular.


Aquí está mi solución, cargas desde .json para permitir cambios sin reconstruir

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); } }

y config.json

{ "apiUrl": "http://localhost:3000/api" }


Aquí están mis dos soluciones para esto

1. Almacenar en archivos json

Simplemente haga un archivo json y $http.get() su componente por el $http.get() . Si necesitaba esto muy bajo, entonces es bueno y rápido.

2. Almacenar utilizando servicios de datos

Si desea almacenar y usar en todos los componentes o tiene un gran uso, es mejor usar el servicio de datos. Me gusta esto :

  1. Simplemente cree una carpeta estática dentro de la carpeta src/app .

  2. Cree un archivo llamado como fuels.ts en la carpeta estática. Puede almacenar otros archivos estáticos aquí también. Deje definir sus datos de esta manera. Suponiendo que tenga datos de combustibles.

__

export const Fuels { Fuel: [ { "id": 1, "type": "A" }, { "id": 2, "type": "B" }, { "id": 3, "type": "C" }, { "id": 4, "type": "D" }, ]; }

  1. Cree un nombre de archivo static.services.ts

__

import { Injectable } from "@angular/core"; import { Fuels } from "./static/fuels"; @Injectable() export class StaticService { constructor() { } getFuelData(): Fuels[] { return Fuels; } }`

  1. Ahora puede hacer que esté disponible para cada módulo

simplemente importe en el archivo app.module.ts como este y cambie los proveedores

import { StaticService } from ''./static.services''; providers: [StaticService]

Ahora use esto como StaticService en cualquier módulo.

Eso es todo.


Descubrí cómo hacer esto con InjectionTokens (vea el ejemplo a continuación), y si su proyecto fue construido usando la Angular CLI , puede usar los archivos de entorno que se encuentran en /environments para la application wide settings estática como un punto final de API, pero dependiendo de su proyecto requisitos que probablemente terminará usando ambos, ya que los archivos de entorno son solo literales de objeto, mientras que una configuración inyectable que usa InjectionToken puede usar las variables de entorno y dado que es una clase puede tener lógica aplicada para configurarlo en función de otros factores en la aplicación, como datos iniciales de solicitud http, subdominio, etc.

Ejemplo de fichas de inyección

/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 { }

Ahora puede simplemente DI en cualquier componente, servicio, 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); } // ... }

Luego, también puede escribir check the config utilizando el AppConfig exportado.


No es aconsejable utilizar los archivos de environment.*.ts para la configuración de URL de su API. Parece que deberías porque esto menciona la palabra "medio ambiente".

Usar esto es en realidad una configuración en tiempo de compilación . Si desea cambiar la URL de la API, deberá volver a compilar. Eso es algo que no quieres hacer ... solo pregúntale a tu amigable departamento de control de calidad :)

Lo que necesita es la configuración en tiempo de ejecución , es decir, la aplicación carga su configuración cuando se inicia.

Algunas otras respuestas tocan esto, pero la diferencia es que la configuración debe cargarse tan pronto como se inicie la aplicación , de modo que pueda ser utilizada por un servicio normal cuando lo necesite.

Para implementar la configuración de tiempo de ejecución:

  1. Agregue un archivo de configuración JSON a la carpeta /src/assets/ (para que se copie en la compilación)
  2. Cree un AppConfigService para cargar y distribuir la configuración
  3. Cargue la configuración usando un APP_INITIALISER

1. Agregue el archivo de configuración a /src/assets

Podría agregarlo a otra carpeta, pero necesitaría decirle a la CLI que es un activo en angular.json . Comience usando la carpeta de activos:

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

2. Crear AppConfigService

Este es el servicio que se inyectará cada vez que necesite el valor de configuración:

@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. Cargue la configuración usando un APP_INITIALISER

Para permitir que AppConfigService se inyecte de forma segura, con la configuración cargada por completo, necesitamos cargar la configuración en el momento del inicio de la aplicación. Es importante destacar que la función de fábrica de inicialización debe devolver una Promise para que Angular sepa esperar hasta que termine de resolverse antes de finalizar el inicio:

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 { }

Ahora puede inyectarlo donde lo necesite y toda la configuración estará lista para leer:

@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; } }

No puedo decirlo con suficiente fuerza, configurar sus URL de API como configuración en tiempo de compilación es un antipatrón . Usar configuración de tiempo de ejecución.


Si está utilizando angular-cli , hay otra opción:

La CLI angular proporciona archivos de entorno en src/environments (los predeterminados son environment.ts (dev) y environment.prod.ts (producción)).

Tenga en cuenta que debe proporcionar los parámetros de configuración en todos environment.* archivos de environment.* , Por ejemplo,

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__'' };

y úselos en su servicio (el archivo de entorno correcto se elige automáticamente):

api.service.ts

// ... other imports import { environment } from ''../../environments/environment''; @Injectable() export class ApiService { public apiRequest(): Observable<MyObject[]> { const path = environment.apiEndpoint + `/objects`; // ... } // ... }

Lea más sobre los entornos de aplicación en Github (Angular CLI versión 6) o en la guía oficial Angular (versión 7) .