【发布时间】:2017-09-17 16:50:00
【问题描述】:
我使用 angualr2-library yeoman 生成器创建了公司内部库。
一些 Angular 服务在我们当前的应用程序中使用环境变量(每个 env 上的 api 端点都发生了变化)。我想知道将当前环境对象传递给 angular2 库服务的最佳方法是什么?
【问题讨论】:
-
你得到这个答案了吗?我想做同样的事情
标签: angular angular-cli
我使用 angualr2-library yeoman 生成器创建了公司内部库。
一些 Angular 服务在我们当前的应用程序中使用环境变量(每个 env 上的 api 端点都发生了变化)。我想知道将当前环境对象传递给 angular2 库服务的最佳方法是什么?
【问题讨论】:
标签: angular angular-cli
如果您仍在寻找解决方案,这就是我如何完成与您所要求的类似的事情(使用 Angular 4.2.4)。
在您的AppModule(或您要导入库的位置)中,调用LibraryModule 上的forRoot() 方法。借助此功能,您可以将任何配置值传递给您的库,例如您应用的环境。
import {environment} from "../environments/environment";
...
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
...
LibraryModule.forRoot(environment)
],
bootstrap: [AppComponent]
})
export class AppModule {
}
你LibraryModule 当然需要提供forRoot() 方法。
然后在 providers 数组中你可以提供服务,值and more。在这种情况下,为简单起见,'env' 充当持有给定环境对象的令牌。您也可以改用InjectionToken。
@NgModule({
...
})
export class LibraryModule {
public static forRoot(environment: any): ModuleWithProviders {
return {
ngModule: LibraryModule,
providers: [
ImageService,
{
provide: 'env', // you can also use InjectionToken
useValue: environment
}
]
};
}
}
由于令牌env 现在由您的LibraryModule 提供,您可以将其注入其所有子服务或组件中。
@Injectable()
export class ImageService {
constructor(private http: Http, @Inject('env') private env) {
}
load(): Observable<any> {
// assume apiUrl exists in you app's environment:
return this.http.get(`${this.env.apiUrl}/images`)
.map(res => res.json());
}
}
希望对你有帮助!
【讨论】:
environment 值并想在我的appModule 中显示更改的环境值怎么办?我可以这样做吗。因为当 LibraryModule 在应用模块之外更改环境值时,它不会反映在应用模块中@Günter Zöchbauer
我在a GitHub issue 中找到了该问题的替代解决方案。 GitHub线程中的解决方案有一个错误(错字),所以我在这里包括了固定的解决方案:
首先,将提供程序添加到包含您的环境文件的顶级 AppModule。
import {environment} from '../environments/environment'
@NgModule({
providers: [
{provide: 'environment', useValue: environment}
]
// object properties omitted for brevity...
})
class AppModule {}
最后,使用 Inject 装饰器将您的环境文件包含在您希望的应用程序的任何其他部分(库或其他)中:
@Component({
// object properties omitted for brevity
})
class MyComponent {
private environment
constructor(
@Inject('environment')
environment
) {
this.environment = environment
}
}
【讨论】:
使用 Angular 11 的完整工作解决方案。假设您使用命令 ng generate library library1 生成了一个名为 library1 的库。
AppModule 文件
// Your other imports ...
import { Library1Module } from 'library1';
import { environment } from 'src/environments/environment';
@NgModule({
declarations: [AppComponent],
imports: [
BrowserModule,
// Pass the data you want to share with your library. Here we will pass 'apiUrl'.
Library1Module.forRoot({ apiUrl: environment.apiUrl }),
AppRoutingModule
]
})
export class AppModule { }
library1.module.ts('Library1' 模块主文件):
import { ModuleWithProviders, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Configurations } from './configurations';
import { Library1Component } from './library1.component';
@NgModule({
declarations: [Library1Component],
imports: [CommonModule],
exports: [Library1Component]
})
export class Library1Module {
// Create this static method in the library module.
public static forRoot(config: Configurations): ModuleWithProviders<Library1Module> {
return {
ngModule: Library1Module,
providers: [
{ provide: Configurations, useValue: config }
]
};
}
}
configurations.ts(在 'projects\library1\src\lib' 文件夹中声明这个类)。声明您需要从“环境”文件中获取的所有配置。
export class Configurations {
public apiUrl: string;
constructor() {
this.apiUrl = '';
}
}
library1.service.ts('Library1Service' 将接收配置对象)。
import { Injectable, Optional } from '@angular/core';
import { Configurations } from './configurations';
@Injectable({
providedIn: 'root'
})
export class Library1Service {
private _apiUrl = 'No value';
constructor(@Optional() config?: Configurations) {
if (config) {
this._apiUrl = config.apiUrl;
}
}
get apiUrl() {
return this._apiUrl;
}
}
library1.component.ts(使用配置数据的Library1 组件)。
import { Component } from '@angular/core';
import { Library1Service } from '../public-api';
@Component({
selector: 'lib-library1',
template: `
<p>
This component inside "library1" library and reads the values from "environment.ts" file.
</p>
<h1>API URL : {{apiUrl}}</h1>`
})
export class Library1Component {
apiUrl = '';
constructor(library1Service: Library1Service) {
this.apiUrl = library1Service.apiUrl;
}
}
app.component.ts(使用 library1 组件确认 URL 已传递到您的库)。
.......
<lib-library1></lib-library1>
.......
【讨论】:
here我认为有更好的方法
我认为你们会发现这很有用:使用抽象类作为可交换行为的依赖注入标记
我在一个 Nx 项目中有 3 个 Angular 应用程序,它们共享一些常见的环境变量。公共站点、私人门户和管理应用程序。在我的库中,我使用了一个定义公共环境变量的抽象环境类。
export abstract class Environment {
abstract readonly production: boolean;
abstract readonly appUrls: {
readonly public: string;
readonly portal: string;
readonly admin: string;
};
}
然后我将3个environment.ts文件改成如下。
import { Environment } from '@my-lib-prefix/common';
class EnvironmentImpl implements Environment {
production = false;
appUrls = {
public: 'http://localhost:4200',
portal: 'http://localhost:4201',
admin: 'http://localhost:4202'
};
}
export const environment = new EnvironmentImpl(); environment.prod.ts 当然与 dev environment.ts 是对称的。然后我在每个 Angular 应用程序的根 app.module.ts 中提供各自的环境依赖项。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { Environment } from '@my-lib-prefix/common';
import { environment } from '../environments/environment';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [{ provide: Environment, useValue: environment }],
bootstrap: [AppComponent]
})
export class AppModule {}
现在任何组件都可以以干净、通用的方式注入环境依赖项。
import { Component } from '@angular/core';
import { Environment } from '@my-lib-prefix/common';
@Component({
selector: 'my-login',
templateUrl: './my-login.component.html'
})
export class MyLoginComponent {
constructor(private env: Environment) {}
}
它强制每个 environment.ts 实现抽象类中定义的“通用”环境变量。此外,每个各自的 EnvironmentImpl 都可以使用特定于应用程序的特定环境变量进行扩展。这种方法看起来非常灵活和干净。干杯! ^_^
【讨论】:
如果您尝试为 firebase 传递环境变量,只需在您的库中使用它:
@NgModule({
declarations: [MyAngularComponent],
exports: [MyAngularComponent],
imports: [
AngularFireModule,
AngularFirestoreModule,
CommonModule
]
})
export class MyAngularModule {
public static forRoot(firebaseConfig: FirebaseOptions): ModuleWithProviders<MyAngularModule> {
return {
ngModule: MyAngularModule,
providers: [
{ provide: FIREBASE_OPTIONS, useValue: firebaseConfig }
]
}
}
}
然后像 AngularFire 一样导入它...
MyAngularModule.forRoot(environment.firebase)
来自这个帖子:pass angularFire config imported in library using forRoot
【讨论】:
如果您仍在寻找答案。 在当前版本(即 Angular > 6)中,您无需执行任何操作。
angular-cli 命令“ng build --prod(用于生产)& ng build(用于开发)”将为您处理。
示例:如果您在开发环境中运行项目,则所有变量都从 src/environments/environment.ts 中捕获。 在您的组件库项目中,只需导入“import { environment } from 'environments/environment';” (请确保路径)将根据 angular-cli build 命令处理环境。
【讨论】: