Je vous appelle pour vous aider sur la méthode à utiliser ici: j'ai testé beaucoup de choses pour résoudre mon problème et j'ai au moins 4 solutions de travail, mais je ne sais pas laquelle serait la meilleure et si certains d'entre eux ne fonctionnent que parce que j'ai eu d'autres effets secondaires et ne devraient pas être utilisés ...
Je n'ai rien trouvé dans la documentation qui m'indique une de ces solutions (ou une autre)
Premièrement, voici ma situation: je construis une application qui se connecte à une API pour les données et construit différentes sections, chacune contenant des données.
J'ai construit les sections du site pour qu'elles soient des modules, mais elles partagent un service nommé DataService (chacun de ces modules utilisera DataService pour obtenir et traiter les données).
My DataService a besoin d'un fichier de configuration avec un certain nombre d'options spécifiques à chaque section et stockées dans son propre dossier.
J'ai donc besoin de fournir DataService séparément pour chaque section, dans la section providers du fichier module.ts, et cela semblait être une bonne pratique d'éviter de copier DataService dans chaque module ...
Donc, l'architecture des fichiers serait:
--Dashboard module
----data.service.ts
----Section1 module
------Section1 config file
----Section2 module
------Section2 config file
J'ai essayé plusieurs choses qui semblent toutes fonctionner dans le fichier de module de section:
Solution 1: injection
(Je ne pouvais pas faire fonctionner l'injection sans guillemets, même si je ne l'avais vue nulle part)
Fichier de module:
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 { }
Fichier de section:
@Injectable()
export class DataService {
constructor(@Inject('VIEW_CONFIG') private viewConfig : any) {}
}
Solution 2: fournisseur d'usine
Ne fonctionne pas après le redémarrage du serveur (voir la mise à jour)}
Inspiré de https://angular.io/docs/ts/latest/guide/dependency-injection.html#!#factory-provider
Fichier de module:
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 { }
Fichier de section:
@Injectable() export class DataService { constructor(private viewConfig : any) {} }
Solution 3: fournisseur personnalisé avec instanciation directe
Ne fonctionne pas après le redémarrage du serveur (voir la mise à jour)}
Fichier de module:
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 { }
Fichier de section:
@Injectable() export class DataService { constructor(private viewConfig : any) {} }
Solution 4: fournisseur personnalisé avec usine
Ne fonctionne pas après le redémarrage du serveur (voir la mise à jour)}
Très similaire à la solution 3 ...
Fichier de module:
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 { }
Fichier de section:
@Injectable() export class DataService { constructor(private viewConfig : any) {} }
Solution 5 Utilisation d'une usine exportée à partir du fichier de service ET et du jeton d'injection
Fichier de module:
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 { }
Fichier de section:
@Injectable()
export class DataService {
constructor(private viewConfig : any) {}
}
export function dataServiceFactory(configObject) {
return new DataService(configObject);
}
Je suis ouvert à toute critique, idée, nouvelle piste de quelque nature que ce soit sur "Quelle serait la bonne solution?" ou même "est la bonne solution parmi ceux-ci?"
Merci beaucoup ! :RÉ
UPDATE À un moment donné, j'ai réalisé que mon Angular-CLI se comportait étrangement et que certaines de ces méthodes ne fonctionnaient pas si je tuais mon serveur local et faisais un "ng serve". Ce qui est encore plus étrange, c'est que ça ne marche pas juste après avoir tué le serveur local de la CLI et l'avoir redémarré, mais la prochaine fois que j'enregistre un fichier et que la CLI est recompilée, cela fonctionne très bien ...
Solution 1: fonctionne toujours
Solution 2/Solution 3: échec avec erreur:
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
Solution 4: échec avec erreur:
Error encountered resolving symbol values statically. Reference to a non-exported function
Solution ajoutée 5
Mon approche d'utilisation des données de configuration de la vue est la suivante:
Mon fichier de configuration:
export const IBO_DETAILS_GENERAL = {
iboCode: 'IBOsFormCodeField',
iboGivenName: 'IBOsFormGivenNameField',
iboFamilyName: 'IBOsFormFamilyNameField',
iboEmail: 'IBOsFormEmailField',
};
export const IBO_DETAILS_ACCOUNT = [];
Mon composant de vue:
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;
Ainsi, de cette façon, j'ai ma config
dans formFields
. Et je peux l'utiliser n'importe où dans la portée de ce composant.
Je l'utilise actuellement pour générer des champs de formulaire dynamiques (entrée, sélection, etc.) en fonction des données que je reçois de mon appel API.
Mais vous pouvez utiliser cet objet (formFields
dans mon cas) pour rechercher ce dont vous avez besoin et l'envoyer à votre service en tant que paramètre.
Aussi, bon travail pour mettre le service partagé à un niveau supérieur. Je crois que c'est la meilleure approche. Mais je ne l'ajouterais pas à providers
sur chaque composant, je l'ajouterais au module du composant. Comme ça:
@NgModule({
declarations: [
ChildComp1,
ChildComp2
],
imports: [
],
providers: [
SharedService
]
})
export class SectionModule {
}
De cette façon, ChildComp1
et ChildComp2
auront accès à SharedService
sans avoir à l'ajouter dans le code du composant.
Cela fonctionne bien lorsque, par exemple, vous définissez une section de Utilisateur. À l'intérieur, par exemple, UsersModule
vous déclarez dans providers
votre UsersSharedService
et ensuite dans declarations
vous déclarez votre UsersLeftPanel
et UsersRightPanel
(exemples).
Mise à jour 1:
Exemple d'utilisation de config dans le service.
Imaginez que le service partagé utilise cette méthode:
getData() {
// do Stuff
let myData = {}; // Result of the stuff we did
this.dataSubject.next(myData);
}
Dans votre composant, vous appelez ceci comme ceci:
this.myService.getData();
Droite?
Maintenant, rappelez-vous que notre config a été déclarée? Ajoutez-le à l'appel.
this.myService.getData(this.formFields);
Et à notre service:
getData(currentConfig) {
// do Stuff depending on currentConfig obj received as parameter
let myData = {}; // Result of the stuff we did
this.dataSubject.next(myData);
}
De cette façon, vous appelez la méthode getData()
de notre service partagé en transmettant différentes configurations. De cette façon, vous n'avez pas à inclure votre service dans plusieurs providers
et vous n'avez pas à copier/coller la logique qui gère la configuration, vous l'avez dans votre service partagé et, par conséquent, à tous vos enfants. y avoir accès.
Mise à jour 2:
Suite à votre approche Solution 5, je pense que vous manquez multi: true
.
Essaye ça:
export function dataServiceFactory(configObject) {
return () => new DataService(configObject);
}
providers: [
{ provide: VIEW_CONFIG, useValue: viewConfig },
{ provide : DataService,
useFactory: dataServiceFactory,
deps : [VIEW_CONFIG],
multi: true }
]})
La return
dans la fonction exportée est la clé: return () =>
.
Voici comment je l'ai dans mon projet:
export function initConfigFactory(userConfig: UserConfig) {
return () => userConfig.getUsersConfig();
}
Où userConfig.getUsersConfig()
est un appel de service qui obtient la configuration de l'utilisateur.
providers: [
{
provide: APP_INITIALIZER,
useFactory: initConfigFactory,
deps: [UserConfig],
multi: true
}
]
Ceci est très proche de votre Solution 5, essayez-le!