一尘不染

我应该如何在Angular2中制作可配置模块

angularjs

我想知道在angular2中设置可配置模块的最佳方法是什么。在angular1中,这通常是通过提供程序完成的。在对它们进行了相当多的更改之后,您将如何将配置参数传递给可重用的ng2模块/指令/组件?

一个NG1例子

// configuring a (third party) module    
.config(function (angularPromiseButtonsProvider) {
  angularPromiseButtonsProvider.extendConfig({
    spinnerTpl: '<div class="other-class"></span>',
    disableBtn: false
  });
});

 // setting up the provider
.provider('angularPromiseButtons', function angularPromiseButtonsProvider() {
    var config = {
        spinnerTpl: '<span class="btn-spinner"></span>',
        priority: 0,
        disableBtn: true,
    };

    return {
        extendConfig: function(newConfig) {
            config = angular.extend(config, newConfig);
        },

        $get: function() {
            return {
                config: config
            };
        }
    };
})

// using the result in the directive, etc.
.directive('promiseBtn', function(angularPromiseButtons){
    var config = angularPromiseButtons.config;
})

这个问题基本上与问题相同,但针对的是angular2。


阅读 214

收藏
2020-07-04

共1个答案

一尘不染

有几种配方,可以单独使用或一起使用。

配置服务

通常需要提供服务来提供键/值形式的必要配置。

可能有多个配置服务来配置一个应用程序实体,例如someConfig用于通用用户定义的配置以及someDefaultConfig所有可能被更改的默认值。例如,someConfig可能包含始终由用户定义的身份验证凭据,并且someDefaultConfig可能包含默认的钩子回调,身份验证提供程序的深度设置等。实现此目的的最简单方法是使用合并配置对象Object.assign

强制配置服务

一个需要用户显式定义配置服务的配方,它基本上使用DI来表示某些模块如果没有适当的配置将无法工作。

AngularJS

// third-party module
// will fail if someConfig wasn't defined by the user
angular.module('some', []).factory('someService', (someConfig) => { ... })

// user-defined module
angular.module('app', ['some']).constant('someConfig', { foo: 'foo' });

角度的

// third-party module
export const SOME_CONFIG = new InjectionToken('someConfig');

@Injectable
class SomeService {
  constructor(@Inject(SOME_CONFIG) someConfig) { ... }
}

@NgModule({ providers: [SomeService] })
export class SomeModule {}

// user-defined module
@NgModule({
  imports: [SomeModule],
  providers: [{ provide: SOME_CONFIG, useValue: { foo: 'foo' } }]
)
export class AppModule {}

可选配置服务,具有可覆盖的空值

这是先前配方的略微变化,唯一的区别是,如果用户未定义配置服务,则默认值为空不会使应用程序失败:

AngularJS

// third-party module
angular.module('some', [])
.constant('someConfig', {})
...

角度的

// third-party module
@NgModule({ providers: [..., { provide: SOME_CONFIG, useValue: {} }] })
export class SomeModule {}
...

可选配置服务

或者,可以将配置服务完全设为可选注入。

AngularJS

// third-party module
angular.module('some', []).factory('someService', ($injector) => {
  const someConfig = $injector.has('someConfig') ? $injector.get('someConfig') : {};
  ...
})
...

角度的

// third-party module
export const SOME_CONFIG = new InjectionToken('someConfig');

@Injectable
class SomeService {
  constructor(@Inject(SOME_CONFIG) @Optional() someConfig) {
    this.someConfig = someConfig !== null ? someConfig : {};
    ...
  }
}

@NgModule({ providers: [SomeService] })
export class SomeModule {}
...

forRoot方法

forRoot静态模块方法是Angular路由器模块和众多第三方模块遵循的约定如指南中所述,该方法返回一个实现的对象ModuleWithProviders

基本上,它提供了一个基于forRoot(...)参数动态定义模块提供程序的机会。这可以被视为AngularJS
configproviderAngular中不存在的单元的替代。

AngularJS

// third-party module
angular.module('some', [])
.constant('someDefaultConfig', { bar: 'bar' })
.provider('someService', function (someDefaultConfig) {
  let someMergedConfig;

  this.configure = (config) => {
    someMergedConfig = Object.assign({}, someDefaultConfig, config);
  };
  this.$get = ...
});

// user-defined module
angular.module('app', ['some']).config((someServiceProvider) => {
  someServiceProvider.configure({ foo: 'foo' });
});

角度的

// third-party module
export const SOME_CONFIG = new InjectionToken('someConfig');
export const SOME_DEFAULT_CONFIG = new InjectionToken('someDefaultConfig');

@Injectable
class SomeService {
  constructor(
    @Inject(SOME_CONFIG) someConfig,
    @Inject(SOME_DEFAULT_CONFIG) someDefaultConfig
  ) {
    this.someMergedConfig = Object.assign({}, someDefaultConfig, someConfig);
    ...
  }
}

@NgModule({ providers: [
  SomeService,
  { provide: SOME_DEFAULT_CONFIG, useValue { bar: 'bar' } }
] })
export class SomeModule {
  static forRoot(config): ModuleWithProviders {
    return {
      ngModule: SomeModule,
      providers: [{ provide: SOME_CONFIG, useValue: config }]
    };
  }
}

// user-defined module
@NgModule({ imports: [SomeModule.forRoot({ foo: 'foo' })] })
export class AppModule {}

APP_INITIALIZER多提供商

Angular APP_INITIALIZERMulti-
provider允许为应用程序提供异步初始化例程。

APP_INITIALIZER与AngularJS配置阶段有一些相似之处。APP_INITIALIZER例程易受竞争条件的影响,类似于AngularJS中的configrun块。例如,由于循环依赖于另一个Router组件,因此可用于在根组件中进行注入,但不能在其中进行注入。APP_INITIALIZER``APP_INITIALIZER

同步初始化程序

AngularJS

...
// user-defined module
angular.module('app', ['some']).config((someServiceProvider) => {
  someServiceProvider.configure({ foo: 'foo' });
});

角度的

...
// user-defined module
export function someAppInitializer(someService: SomeService) {
  return () => {
    someService.configure({ foo: 'foo' });
  };
}

@NgModule({
  imports: [SomeModule],
  providers: [{
    provide: APP_INITIALIZER,
    multi: true,
    useFactory: someAppInitializer,
    deps: [SomeService]
  }]
})
export class AppModule {}

异步初始化程序

初始化可能涉及从远程源获取配置以配置服务。单个AngularJS应用程序无法实现的功能。这需要具有另一个应用程序来初始化和引导主模块。这种情况自然是由处理的APP_INITIALIZER

AngularJS

...
// user-defined module
angular.module('app', ['some']);

angular.module('appInitializer', [])
.factory('initializer', ($document, $http) => {
  return $http.get('data.json')
  .then((result) => result.data)
  .then((data) => {
    $document.ready(() => {
      angular.bootstrap($document.find('body'), ['app', (someServiceProvider) => {
        someServiceProvider.configure(data);
      }]);
    });
  });
});

angular.injector(['ng', 'appInitializer'])
.get('initializer')
.catch((err) => console.error(err));

角度的

...
// user-defined module
export function someAppInitializer(http: HttpClient, someService: SomeService) {
  return () => {
    return http.get('data.json').toPromise()
    .then(data => {
      someService.configure(data);
    });
  };
}

@NgModule({
  imports: [SomeModule],
  providers: [{
    provide: APP_INITIALIZER,
    multi: true,
    useFactory: someAppInitializer,
    deps: [HttpClient, SomeService]
  }]
})
export class AppModule {}
2020-07-04