【问题标题】:Angular Access data from Service来自服务的角度访问数据
【发布时间】:2018-01-20 02:53:29
【问题描述】:

我正在使用 Angular 5 和 httpclient。我不喜欢内置环境来设置我需要使用的环境 api url。我已切换到使用 nginx.conf 进行 api 调用,该调用返回一个 json,其中我的 api url 是从环境变量设置的。

我有一项服务,我正在调用 http.get 来获取 json 配置文件。

@Injectable()
export class ConfigurationService {
private baseUrl = 'https://someUrl.com';

constructor( private http: HttpClient ) {

}

getConfig(): Observable<any> { 
  return this.http
  .get(this.baseUrl + '/config')
  .map(res=>res);   
};
}

此服务在应用程序首次启动时从我的 app.component.ts 调用。

我有一个 constants.ts 文件,我想用它来引用我的 api url

export class Constants {    

public api1 = //NEED API1 URL FROM SERVICE HERE;
public api2= //NEED API2 URL FROM SERVICE HERE;

从服务中引入数据的最佳方式是什么?我的常量文件不是一个组件,只是一个类。

【问题讨论】:

    标签: angular


    【解决方案1】:

    对于这样的事情,您应该使用应用初始化服务。应用初始化程序在您的应用程序中的所有其他内容之前运行,并且您的应用程序在完成之前不会加载。它的结构是这样的:

    import { Injectable, APP_INITIALIZER } from '@angular/core';
    
    export interface AppConfig {
        api1: string;
        api2: string;
    }
    
    @Injectable()
    export class ConfigService {
      protected config: AppConfig;
    
      constructor(private _http: HttpClient) {
      }
    
      getConfigData(): Observable<any> {
        return this._http.get<AppConfig>('... your config url...')
          .catch(error => {
            alert('Unable to read configuration file:' + JSON.stringify(error));
            return Observable.throw(error);
          });
      }
    
      public load() {
         return new Promise((resolve, reject) => {
           this.getConfigData()
             .subscribe(
               config => {
                 this.config= config ;
                 resolve(true);
               },
               err => resolve(err)
             );
         });
      }
    }
    
    export function ConfigServiceInitFactory(configService: ConfigService) {
      return () => configService.load();
    }
    
    export const ConfigServiceInitProvider = {
      provide: APP_INITIALIZER,
      useFactory: ConfigServiceInitFactory,
      deps: [ConfigService],
      multi: true
    }
    

    然后您将 ConfigServiceInitProvider 与 ConfigService 一起添加到您的 AppModule 提供程序(将 ConfigService 放在 ConfigServiceInitProvider 之前),然后在需要的地方注入 ConfigService 并访问配置值,例如:

    constructor(private _config: ConfigService) {
        this.apiBase = this._config.config.api1;
    }
    

    我不喜欢 _config.config 的重复性,所以我通常也会在我的配置服务上定义 getter,例如:

    get api1() { return this.config.api1 }
    

    然后你就可以打电话了:

    this.apiBase = this._config.api1;
    

    但是,如果您询问是否可以在 constants.ts 文件中设置值,以便可以像这样使用它:

    import {Constants} from 'app/constants';
    
    constructor() {
       this.apiBase = Constants.api1;
    }
    

    在运行时从服务器加载的内容无法做到这一点,因为当您运行构建命令时,您的所有打字稿都被编译为 javascript。因此,从逻辑上讲,如果不将其作为服务值提供,您就无法使用从服务器加载的内容创建构建。您将始终需要注入服务。

    解决此问题的唯一方法是在运行构建之前插入不同的常量文件,然后您就无需从服务器调用配置。但这有它自己的缺点,例如它需要完全重建和重新部署以更新配置值,这首先与配置点相悖。

    【讨论】:

    • 这非常有效。根据您的评论,我没有在 constants.ts 文件中设置值。相反,我将配置服务注入到我的其他进行 api 调用的服务中。我确实有一个问题,但你为什么要保护配置?受保护的配置:AppConfig;我必须公开访问 api1 和 api2
    • 我基本上复制了我在所有项目中使用的服务。我使它受到保护,因为我与其他开发人员一起工作,我不希望任何人能够更改影响整个应用程序的配置值。我定义了我在帖子中概述的公共吸气剂以获取数据。至少应该定义一个私有 _config 和 public get config() 来传递它的副本,而不是原始的。
    【解决方案2】:

    您应该将constant 类作为@Injectable 并具有如下设置值的方法

    @Injectable()
    export class Constants {    
    
       api1 :string; // NEED API1 URL FROM SERVICE HERE;
    
       api2: string; // NEED API2 URL FROM SERVICE HERE
    
    
       setValueApi1(val){
           this.api1 = val;
       }
    }
    

    您可以将 this 注入到构造函数中,并通过传递响应来调用方法来设置值,如下所示

    @Injectable()
    export class ConfigurationService {
    private baseUrl = 'https://someUrl.com';
    
    constructor( private http: HttpClient,private constants:Constants ) {  }
    
        getConfig(): Observable<any> { 
          return this.http
          .get(this.baseUrl + '/config')
          .map(res=>res)
        }
    }
    

    在您的组件中,您可以通过调用以下方法订阅响应值并设置 api 值

    this.getConfig().subscribe(response => {
        this.constants.setValueApi1(response))
    })
    

    【讨论】:

    • 谢谢你。我确实实现了这个,它工作得很好,我只是碰巧用 APP_INITIALIZER 回答了上面的答案
    【解决方案3】:

    一个简单的方法是这样的:

    class Constants {
        public api1: string;
        public api2: string;
    
        public setApi1(api: string) {}
        public setApi2(api: string) {}
    }
    
    export const CONSTANTS: Constants = {
        api1: "DEFAULT API 1",
        api2: "DEFAULT API 2",
        setApi1(api: string) : void {
            this.api1 = api;
        },
        setApi2(api: string) : void {
            this.api2 = api;
        }
    }
    

    然后只需在需要持久性的地方导入您的 const

    import {CONSTANTS} from "../path/to/constant.ts";
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-22
      • 2017-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-10
      相关资源
      最近更新 更多