如何创建可配置服务 Angular 4
How to create configurable service Angular 4
我想创建一个服务,以便在几个 angular 应用程序中重复使用。
我正在使用 angular-cli。
我希望服务是可配置的。换句话说,让每个应用程序能够使用不同的配置参数实例化服务,使用 DI。
该服务将位于共享库中,因此它无法从父应用程序导入特定文件路径以获取配置参数,它必须通过 DI 获取它们。
我尝试按照说明进行操作 here,因为这篇文章准确描述了我面临的问题,但是我收到了一个错误:
ERROR Error: No provider for String!
at injectionError (core.es5.js:1169)
at noProviderError (core.es5.js:1207)
at ReflectiveInjector_.webpackJsonp.../../../core/@angular/core.es5.js.ReflectiveInjector_._throwOrNull (core.es5.js:2649)
at ReflectiveInjector_.webpackJsonp.../../../core/@angular/core.es5.js.ReflectiveInjector_._getByKeyDefault (core.es5.js:2688)
at ReflectiveInjector_.webpackJsonp.../../../core/@angular/core.es5.js.ReflectiveInjector_._getByKey (core.es5.js:2620)
at ReflectiveInjector_.webpackJsonp.../../../core/@angular/core.es5.js.ReflectiveInjector_.get (core.es5.js:2489)
at resolveNgModuleDep (core.es5.js:9533)
at _createClass (core.es5.js:9572)
at _createProviderInstance (core.es5.js:9544)
at resolveNgModuleDep (core.es5.js:9529)
此外,来自 zone.js:
zone.js:643 Unhandled Promise rejection: No provider for String! ; Zone: <root> ; Task: Promise.then ; Value: Error: No provider for String!
这是我的相关代码:
main.ts:
...
import { provideAuthService } from 'shared-library';
...
platformBrowserDynamic().bootstrapModule(AppModule, [provideAuthService('Good Day')]);
app.module.ts:
...
import { AuthService } from 'shared-library';
@NgModule({
declarations: [
...
],
imports: [
...
],
providers: [
AuthService
],
bootstrap: [AppComponent]
})
export class AppModule { }
和auth.service.ts:
...
export function provideAuthService(settings:string) {
return { provide: AuthService, useFactory: () => new AuthService(settings)
}
@Injectable()
export class AuthService {
mgr: UserManager = new UserManager(this.settings);
constructor(private settings:string='Hello') {
...
}
}
提前感谢任何可能在这里提供帮助的人!
您可以遵循 Angular 路由器完成的模式,其中配置对象被定义为可注入的,并且您只能在主应用程序的模块中声明一次。
定义一个新的令牌来标识配置对象:
export const APP_CONFIG = new InjectionToken<string>('AppConfig');
创建您的配置对象可以使用的接口或抽象class。这只会让您更容易维护您的配置对象。这是一个示例,但您可以根据需要定义自己的属性或方法。
export interface AppConfig {
name: string;
baseUrl: string;
}
创建一个新模块来保存可配置服务。该模块将有一个 forRoot()
方法,允许您设置配置对象。它还将进行安全检查,以确保模块只配置一次正确的配置(通过构造函数)。
import { Injectable, NgModule, SkipSelf, Optional } from '@angular/core';
@NgModule({
providers: [
YourServiceClass
]
})
export class ServiceModule {
public static forRoot(config: AppConfig) {
return {
ngModule: ServiceModule,
providers: [
{provide: APP_CONFIG, useValue: config}
]
};
}
public constructor(@Optional() @SkipSelf() parentModule: ServiceModule) {
if(parentModule) {
throw new Error('ServiceModule has already been imported.');
}
}
}
然后您可以将配置对象注入您的服务 class。
@Injectable()
export class YourServiceClass {
public constructor(@Inject(APP_CONFIG) config: AppConfig) {
}
}
要配置服务,您必须在主模块中使用 forRoot
方法。
@NgModule({
imports: [
ServiceModule.forRoot({
name: 'FooBar',
baseUrl: 'http://www.example.com/'
})
]
})
export class MainModule {}
所以这里发生的是 forRoot
方法手动创建模块元数据。有一个令牌 APP_CONFIG
尚未在任何地方声明。因此 forRoot
返回的模块声明它引用了传递给函数的特定值。
顺序或模块导入变得很重要,因为如果模块在主模块之前导入 ServiceModule
,则 APP_CONFIG
将是未定义的。因此,我们在模块构造函数中检查这种情况。如果 ServiceModule
可以注入那么它已经被导入了。这增加了一个限制,即只能使用模块的一个实例,也就是为服务配置的实例。
这是一个很好的模式,我使用了这个模式,但是我 运行 遇到过延迟加载模块想要加载 ServiceModule
的情况。所以如果你想在项目的后期避免头痛。尝试将您的可配置服务限制为模块中的唯一提供者。一旦您开始向模块添加其他内容,您就更有可能需要灵活的加载顺序。
我想创建一个服务,以便在几个 angular 应用程序中重复使用。
我正在使用 angular-cli。
我希望服务是可配置的。换句话说,让每个应用程序能够使用不同的配置参数实例化服务,使用 DI。
该服务将位于共享库中,因此它无法从父应用程序导入特定文件路径以获取配置参数,它必须通过 DI 获取它们。
我尝试按照说明进行操作 here,因为这篇文章准确描述了我面临的问题,但是我收到了一个错误:
ERROR Error: No provider for String!
at injectionError (core.es5.js:1169)
at noProviderError (core.es5.js:1207)
at ReflectiveInjector_.webpackJsonp.../../../core/@angular/core.es5.js.ReflectiveInjector_._throwOrNull (core.es5.js:2649)
at ReflectiveInjector_.webpackJsonp.../../../core/@angular/core.es5.js.ReflectiveInjector_._getByKeyDefault (core.es5.js:2688)
at ReflectiveInjector_.webpackJsonp.../../../core/@angular/core.es5.js.ReflectiveInjector_._getByKey (core.es5.js:2620)
at ReflectiveInjector_.webpackJsonp.../../../core/@angular/core.es5.js.ReflectiveInjector_.get (core.es5.js:2489)
at resolveNgModuleDep (core.es5.js:9533)
at _createClass (core.es5.js:9572)
at _createProviderInstance (core.es5.js:9544)
at resolveNgModuleDep (core.es5.js:9529)
此外,来自 zone.js:
zone.js:643 Unhandled Promise rejection: No provider for String! ; Zone: <root> ; Task: Promise.then ; Value: Error: No provider for String!
这是我的相关代码:
main.ts:
...
import { provideAuthService } from 'shared-library';
...
platformBrowserDynamic().bootstrapModule(AppModule, [provideAuthService('Good Day')]);
app.module.ts:
...
import { AuthService } from 'shared-library';
@NgModule({
declarations: [
...
],
imports: [
...
],
providers: [
AuthService
],
bootstrap: [AppComponent]
})
export class AppModule { }
和auth.service.ts:
...
export function provideAuthService(settings:string) {
return { provide: AuthService, useFactory: () => new AuthService(settings)
}
@Injectable()
export class AuthService {
mgr: UserManager = new UserManager(this.settings);
constructor(private settings:string='Hello') {
...
}
}
提前感谢任何可能在这里提供帮助的人!
您可以遵循 Angular 路由器完成的模式,其中配置对象被定义为可注入的,并且您只能在主应用程序的模块中声明一次。
定义一个新的令牌来标识配置对象:
export const APP_CONFIG = new InjectionToken<string>('AppConfig');
创建您的配置对象可以使用的接口或抽象class。这只会让您更容易维护您的配置对象。这是一个示例,但您可以根据需要定义自己的属性或方法。
export interface AppConfig {
name: string;
baseUrl: string;
}
创建一个新模块来保存可配置服务。该模块将有一个 forRoot()
方法,允许您设置配置对象。它还将进行安全检查,以确保模块只配置一次正确的配置(通过构造函数)。
import { Injectable, NgModule, SkipSelf, Optional } from '@angular/core';
@NgModule({
providers: [
YourServiceClass
]
})
export class ServiceModule {
public static forRoot(config: AppConfig) {
return {
ngModule: ServiceModule,
providers: [
{provide: APP_CONFIG, useValue: config}
]
};
}
public constructor(@Optional() @SkipSelf() parentModule: ServiceModule) {
if(parentModule) {
throw new Error('ServiceModule has already been imported.');
}
}
}
然后您可以将配置对象注入您的服务 class。
@Injectable()
export class YourServiceClass {
public constructor(@Inject(APP_CONFIG) config: AppConfig) {
}
}
要配置服务,您必须在主模块中使用 forRoot
方法。
@NgModule({
imports: [
ServiceModule.forRoot({
name: 'FooBar',
baseUrl: 'http://www.example.com/'
})
]
})
export class MainModule {}
所以这里发生的是 forRoot
方法手动创建模块元数据。有一个令牌 APP_CONFIG
尚未在任何地方声明。因此 forRoot
返回的模块声明它引用了传递给函数的特定值。
顺序或模块导入变得很重要,因为如果模块在主模块之前导入 ServiceModule
,则 APP_CONFIG
将是未定义的。因此,我们在模块构造函数中检查这种情况。如果 ServiceModule
可以注入那么它已经被导入了。这增加了一个限制,即只能使用模块的一个实例,也就是为服务配置的实例。
这是一个很好的模式,我使用了这个模式,但是我 运行 遇到过延迟加载模块想要加载 ServiceModule
的情况。所以如果你想在项目的后期避免头痛。尝试将您的可配置服务限制为模块中的唯一提供者。一旦您开始向模块添加其他内容,您就更有可能需要灵活的加载顺序。