草庐IT

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

coder 2025-02-03 原文

我想知道在 angular2 中设置可配置模块的最佳方法是什么。在 angular1 中,这通常是通过提供者完成的。随着它们发生了相当大的变化,您将如何将配置参数传递给可重用的 ng2 模块/指令/组件?

ng1 example :

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

这基本上与 this one 相同的问题但针对 angular2。

最佳答案

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

配置服务

通常需要有一项服务以键/值形式提供必要的配置。

可能有不止一种配置服务来配置一个应用程序实体,例如someConfig 用于通用的用户定义配置,someDefaultConfig 用于所有应该可能更改的默认值。例如,someConfig 可能包含始终由用户定义的身份验证凭据,someDefaultConfig 可能包含默认 Hook 回调、身份验证提供程序的深层设置等。最简单的方法实现它是将配置对象与 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' });

Angular

// 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', {})
...

Angular

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

可选配置服务

或者,配置服务可以完全可选以进行注入(inject)。

AngularJS

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

Angular

// 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 静态模块方法是 a convention紧随其后的是 Angular 路由器模块和众多第三方模块。 As explained in the guide ,该方法返回一个实现 ModuleWithProviders 的对象.

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

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

Angular

// 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 多 vendor

Angular APP_INITIALIZER多提供商允许为应用程序提供异步初始化例程。

APP_INITIALIZER 与 AngularJS 配置阶段有一些相似之处。 APP_INITIALIZER 例程容易受到竞争条件的影响,类似于 AngularJS 中的 configrun block 。例如,由于对另一个 APP_INITIALIZER 的循环依赖,Router 可用于在根组件中注入(inject),但不能在 APP_INITIALIZER 中注入(inject)。

同步初始化例程

AngularJS

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

Angular

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

Angular

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

关于javascript - 我应该如何在 Angular2 中制作可配置模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43826348/

有关javascript - 我应该如何在 Angular2 中制作可配置模块的更多相关文章

  1. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  2. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  5. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  6. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  7. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  8. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  9. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  10. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

随机推荐