【问题标题】:Angular 4 : how to pass an argument to a Service provided in a module fileAngular 4:如何将参数传递给模块文件中提供的服务
【发布时间】:2017-05-02 09:35:43
【问题描述】:

我正在向您寻求帮助,请教您在这里使用什么方法:我已经测试了很多东西来解决我的问题,并且我至少有 4 个可行的解决方案,但我不知道哪一个是最有效的最好的,如果其中一些只是因为我做过的其他事情的副作用而起作用,不应该使用......

我在文档中找不到任何内容来指向这些解决方案之一(或另一个)

首先,这是我的情况:我正在构建一个应用程序,它连接到数据 API 并构建不同的部分,每个部分都包含 dataviz。

我将网站的各个部分构建为模块,但它们共享一个名为 DataService 的服务(这些模块中的每一个都将使用 DataService 来获取和处理数据)。

我的 DataService 需要一个配置文件,其中包含许多特定于每个部分的选项并存储在它自己的文件夹中。

所以我需要在 module.ts 文件的 providers 部分中为每个部分单独提供 DataService,避免将 DataService 复制到每个模块似乎是一种好习惯......

所以文件的架构是:

--Dashboard module
----data.service.ts
----Section1 module
------Section1 config file
----Section2 module
------Section2 config file

我尝试了多种似乎都可以在部分模块文件中工作的东西:

解决方案一:注入

(即使我没有在任何地方看到这个,我也无法在没有引号的情况下使注入工作)

模块文件:

import { DataService } from '../services/data.service';
import viewConfig from './view.config.json';

@NgModule({
    imports: [ ... ],
    declarations: [ ... ],
    providers: [
        { provide: 'VIEW_CONFIG', useValue: viewConfig },
        DataService,
    ]})
   export class Section1Module { }

部分文件:

@Injectable()
export class DataService {

    constructor(@Inject('VIEW_CONFIG') private viewConfig : any) {}

}

解决方案 2:工厂供应商

ng serve 重启后无法正常工作(请参阅更新)

灵感来自https://angular.io/docs/ts/latest/guide/dependency-injection.html#!#factory-provider

模块文件:

import { DataService } from '../services/data.service';
import viewConfig from './view.config.json';

export let VIEW_CONFIG = new InjectionToken<any>('');
let dataServiceFactory = (configObject):DataService => {
    return new DataService(configObject)
}

@NgModule({
    imports: [ ... ],
    declarations: [ ... ],
    providers: [
        { provide: VIEW_CONFIG, useValue: viewConfig },
        {
            provide : DataService,
            useFactory : dataServiceFactory,
            deps : [VIEW_CONFIG]
        },
    ]})
   export class Section1Module { }

部分文件:

@Injectable()
export class DataService {

    constructor(private viewConfig : any) {}

}

解决方案 3:直接实例化的自定义提供程序

ng serve 重启后无法正常工作(请参阅更新)

模块文件:

import { DataService } from '../services/data.service';
import viewConfig from './view.config.json';

@NgModule({
    imports: [ ... ],
    declarations: [ ... ],
    providers: [
        { provide: DataService, useValue : new DataService(viewConfig) },
    ]})
   export class Section1Module { }

部分文件:

@Injectable()
export class DataService {

    constructor(private viewConfig : any) {}

}

解决方案 4:带工厂的自定义提供程序

ng serve 重启后无法正常工作(请参阅更新)

非常类似于解决方案 3...

模块文件:

import { DataService } from '../services/data.service';
import viewConfig from './view.config.json';

let dataServiceFactory = (configObject) => { return new DataService(configObject) }

@NgModule({
    imports: [ ... ],
    declarations: [ ... ],
    providers: [
         { provide: DataService, useValue : dataServiceFactory(viewConfig) }
    ]})
   export class Section1Module { }

部分文件:

@Injectable()
export class DataService {

    constructor(private viewConfig : any) {}

}

解决方案 5 使用从服务文件 AND 和注入令牌导出的工厂

模块文件:

export const VIEW_CONFIG = new InjectionToken<any>('');

 @NgModule({
    imports: [ ... ],
    declarations: [ ... ],
    providers: [
         { provide: VIEW_CONFIG, useValue: viewConfig },
         { provide : DataService,
           useFactory: dataServiceFactory,
           deps : [VIEW_CONFIG] }
    ]})
   export class Section1Module { }

部分文件:

@Injectable()
export class DataService {
    constructor(private viewConfig : any) {}
}

export function dataServiceFactory(configObject) {
    return new DataService(configObject);
}

我愿意接受任何关于“什么是正确的解决方案?”的批评、想法和任何形式的新领导。甚至“这些解决方案是正确的吗?”

非常感谢! :D


更新 有一次,我意识到我的 Angular-CLI 行为异常,如果我杀死本地服务器并执行“ng serve”,其中一些方法将不起作用。 更奇怪的是,杀死 CLI 本地服务器并重新启动它后,它就不起作用了,但是下次我保存文件并重新编译 CLI 时,它就可以正常工作了……

解决方案 1:仍在工作

解决方案 2 / 解决方案 3:失败并出现错误:

Error encountered resolving symbol values statically. Calling function 
'DataService', function calls are not supported. Consider replacing the 
function or lambda with a reference to an exported function

解决方案 4:失败并出现错误:

Error encountered resolving symbol values statically. Reference to a non-exported function

添加解决方案 5

【问题讨论】:

  • 问题不是我的用例,而是答案为我指明了正确的方向。

标签: angular angular2-services


【解决方案1】:

我使用视图配置数据的方法是这样的:

我的配置文件:

export const IBO_DETAILS_GENERAL = {
    iboCode: 'IBOsFormCodeField',
    iboGivenName: 'IBOsFormGivenNameField',
    iboFamilyName: 'IBOsFormFamilyNameField',
    iboEmail: 'IBOsFormEmailField',
};

export const IBO_DETAILS_ACCOUNT = [];

我的视图组件:

import { IBO_DETAILS_GENERAL } from './ibo-details-formfields';

@Component({
    selector: 'ibo-details-general',
    templateUrl: './ibo-details-general.component.html',
    styles: [],
})
export class IboDetailsGeneral extends FilterDataMappingManipulator implements OnInit, OnDestroy {
    // Initial constants,vectors and component mapping
    private formFields = IBO_DETAILS_GENERAL;

这样,我在formFields 中有我的config。我可以在这个组件范围内的任何地方使用它。

我目前正在使用它来生成动态表单字段(输入、选择等),具体取决于我从 API 调用中获得的数据。

但是您可以使用该对象(在我的情况下为formFields)来查找您需要的内容并将其作为参数发送到您的服务。

此外,在将共享服务提升到更高水平方面做得很好。我相信是最好的方法。但我不会将它添加到每个组件的providers,我会将它添加到组件的模块中。像这样:

@NgModule({
    declarations: [
        ChildComp1,
        ChildComp2
    ],
    imports: [
    ],
    providers: [
        SharedService
    ]
})
export class SectionModule {
}

这样,ChildComp1 和 ChildComp2 将可以访问 SharedService,而无需将其添加到组件的代码中。

例如,当您定义 User 的部分时,这可以正常工作。在里面,比如说,UsersModule 你在providers 中声明你的UsersSharedService 然后在declarations 你声明你的UsersLeftPanel 和UsersRightPanel (示例)。

更新 1:

服务中配置的使用示例。

想象一下共享服务有这个方法:

getData() {
  // do Stuff
  let myData = {}; // Result of the stuff we did
  this.dataSubject.next(myData);
}

在您的组件中,您可以这样称呼:

this.myService.getData();

对吗?

现在,还记得我们已经声明了配置吗?将其添加到通话中。

this.myService.getData(this.formFields);

而且,在我们的服务中:

   getData(currentConfig) {
      // do Stuff depending on currentConfig obj received as parameter
      let myData = {}; // Result of the stuff we did
      this.dataSubject.next(myData);
    }

这样,您调用我们共享服务的getData() 方法传递不同的配置。这样,您不必在许多 providers 中包含您的服务,也不必复制/粘贴处理配置的逻辑,您可以将其包含在您的共享服务中,并且,因此,您所有的孩子都可以使用它。

更新 2:

按照您的解决方案 5 方法,我认为您缺少 multi: true。

试试这个:

export function dataServiceFactory(configObject) {
    return () => new DataService(configObject);
}

providers: [
     { provide: VIEW_CONFIG, useValue: viewConfig },
     { provide : DataService,
       useFactory: dataServiceFactory,
       deps : [VIEW_CONFIG],
       multi: true }
]})

导出函数中的return是key:return () =&gt;。

这就是我在项目中的方式:

export function initConfigFactory(userConfig: UserConfig) {
    return () => userConfig.getUsersConfig();
}

其中userConfig.getUsersConfig() 是获取用户配置的服务调用。

providers: [
    {
        provide: APP_INITIALIZER,
        useFactory: initConfigFactory,
        deps: [UserConfig],
        multi: true
    }
]

这非常接近您的解决方案 5,试试吧!

【讨论】:

  • 据我了解,您不需要您的服务具有特定的配置文件,因此您可以共享父级中提供的实例。我需要单独实例化我的服务,因为它会为每个子模块使用不同的配置信息,所以我不能在顶层提供它......除非我错过了其他东西......
  • @SophieJobez 你好!我更新了我的答案。希望这是我们的解释,尽我所能。觉得有用就告诉我吧! ;)
  • 嗨!我理解您的回答(感谢您抽出时间!),我没有走这条路,因为一种“对象范式”的心理事物让我认为用所有必要的配置实例化我的服务比给每个服务更干净函数的参数...
  • 我的意思是:假设我有 10 个不同的函数可以处理我的数据,并且每个函数都需要一个对于应用程序的这一部分始终相同的参数,但是可以更改另一个部分并稍微改变服务的行为;这意味着每个函数都应该由 this.service.func(configElem) 调用,configElem 取自该部分的 currentConfig...如果我可以在实例化时将所有配置提供给服务,这似乎是不必要的重复... [无论如何我更新了我的原始帖子,因为我错过了 CLI 编译器中的错误]
  • 感谢您,希望任何像我一样用头敲桌子的人都能找到您的完整答案:)!
猜你喜欢
  • 2018-09-05
  • 1970-01-01
  • 2020-11-21
  • 2017-03-01
  • 2017-06-10
  • 1970-01-01
  • 1970-01-01
  • 2014-11-19
  • 2013-04-28
相关资源
最近更新 更多