Angular 4:如何将参数传递给模块文件中提供的服务

Sop*_*bez 9 angular2-services angular

我正在打电话给你,要求你在这里使用什么方法:我已经测试了许多东西来解决我的问题,我至少有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
Run Code Online (Sandbox Code Playgroud)

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

解决方案1:注射

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

模块文件:

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 { }
Run Code Online (Sandbox Code Playgroud)

部分文件:

@Injectable()
export class DataService {

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

}
Run Code Online (Sandbox Code Playgroud)

解决方案2:工厂提供商

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

灵感来自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 { }
Run Code Online (Sandbox Code Playgroud)

部分文件:

@Injectable()
export class DataService {

    constructor(private viewConfig : any) {}

}
Run Code Online (Sandbox Code Playgroud)

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

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

模块文件:

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 { }
Run Code Online (Sandbox Code Playgroud)

部分文件:

@Injectable()
export class DataService {

    constructor(private viewConfig : any) {}

}
Run Code Online (Sandbox Code Playgroud)

解决方案4:自定义提供商与工厂

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

与解决方案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 { }
Run Code Online (Sandbox Code Playgroud)

部分文件:

@Injectable()
export class DataService {

    constructor(private viewConfig : any) {}

}
Run Code Online (Sandbox Code Playgroud)

解决方案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 { }
Run Code Online (Sandbox Code Playgroud)

部分文件:

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

export function dataServiceFactory(configObject) {
    return new DataService(configObject);
}
Run Code Online (Sandbox Code Playgroud)

我对"什么是正确的解决方案?"的批评,想法,任何形式的新领导都持开放态度.甚至"这些是正确的解决方案吗?"

非常感谢 !:d


更新 有一次,我意识到我的Angular-CLI表现得很奇怪,如果我杀了我的本地服务器并且执行了"ng服务",其中一些方法无法正常工作.甚至更奇怪的是,它在杀死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
Run Code Online (Sandbox Code Playgroud)

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

Error encountered resolving symbol values statically. Reference to a non-exported function
Run Code Online (Sandbox Code Playgroud)

添加解决方案5

SrA*_*Axi 2

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

我的配置文件:

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

export const IBO_DETAILS_ACCOUNT = [];
Run Code Online (Sandbox Code Playgroud)

我的视图组件:

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;
Run Code Online (Sandbox Code Playgroud)

所以,这样,我就有了我configformFields。我可以在该组件范围内的任何地方使用它。

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

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

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

@NgModule({
    declarations: [
        ChildComp1,
        ChildComp2
    ],
    imports: [
    ],
    providers: [
        SharedService
    ]
})
export class SectionModule {
}
Run Code Online (Sandbox Code Playgroud)

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

例如,当您定义User部分时,这很有效。在里面,也就是说,您在您UsersModule声明,然后在您声明您的and (examples)providersUsersSharedServicedeclarationsUsersLeftPanelUsersRightPanel

更新1:

服务中配置的使用示例。

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

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

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

this.myService.getData();
Run Code Online (Sandbox Code Playgroud)

正确的?

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

this.myService.getData(this.formFields);
Run Code Online (Sandbox Code Playgroud)

并且,在我们的服务中:

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

这样,您就可以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 }
]})
Run Code Online (Sandbox Code Playgroud)

导出函数return中的关键是:return () =>

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

export function initConfigFactory(userConfig: UserConfig) {
    return () => userConfig.getUsersConfig();
}
Run Code Online (Sandbox Code Playgroud)

userConfig.getUsersConfig()获取用户配置的服务调用在哪里。

providers: [
    {
        provide: APP_INITIALIZER,
        useFactory: initConfigFactory,
        deps: [UserConfig],
        multi: true
    }
]
Run Code Online (Sandbox Code Playgroud)

这与您的解决方案 5非常接近,请尝试一下!