web-dev-qa-db-fra.com

Comment utiliser Factory Provider dans Angular 2

Je dois injecter un service dans un autre service dans une application angular 2. Après avoir lu la documentation que j'ai déduite, la meilleure approche consiste à utiliser un Factory Provider . Deux questions se sont toutefois posées: 

1) La documentation recommande la création d'une classe HeroServiceProvider avec deux "segments de code":

let heroServiceFactory = (logger: Logger, userService: UserService) => {
  return new HeroService(logger, userService.user.isAuthorized);
};

export let heroServiceProvider =
  { provide: HeroService,
    useFactory: heroServiceFactory,
    deps: [Logger, UserService]
  };

Ma question est la suivante: à quoi devrait ressembler la classe? Où faut-il ajouter les segments de code ci-dessus?

2) Comment devrait-on/pourrait-on utiliser cette usine? Je vois, il devrait être importé en tant que:

import { heroServiceProvider } from './hero.service.provider';

@Component({
  selector: 'my-selector',
  template: `
  `,
  providers: [heroServiceProvider]
})

Comment alors le service paramétré souhaité pourrait-il être récupéré et accédé?

8
arjacsoh

J'ai rencontré les mêmes problèmes à injecter sur app_initalizer, après une longue recherche, j'ai trouvé la solution ci-dessous. Peut-être que ceci est une aide pour votre scénario.

@NgModule({
  imports: [ BrowserModule],
  ...
  providers: [
    {
      provide: HeroService,
      useFactory: heroServiceFactory,
      deps: [Logger, UserService],
      multi: true
    }
    ]
})
export class AppModule {}


export function heroServiceFactory = (logger: Logger, userService: UserService) => {
    return new HeroService(logger, userService.user.isAuthorized);
};
16

Je n'ai pas assez de points à commenter contre la réponse de @mgmg, mais voici quelques informations utiles ... 

J'ai utilisé le modèle d'usine du fournisseur donné dans la documentation (et le sujet de cette question) dans ma propre application, mais je continuais à avoir une erreur de compilation.

ERROR in Erreur lors de la résolution statique des valeurs de symbole . Les appels de fonction ne sont pas pris en charge. Envisagez de remplacer la fonction ou lambda avec une référence à une fonction exportée ...

En gros, lorsqu'une dépendance à une fabrique est utilisée dans un module racine, toutes ses dépendances doivent en être fournies. 

Cela signifie que le bloc de code donné dans la réponse de @mgmg doit strictement avoir les services dépendants. 

import { heroServiceProvider } from './hero.service.provider';
import { UserService } from './user.service';
import { Logger }      from './logger.service';

...

@NgModule({

  ...

  providers: [
    Logger,
    UserService,
    heroServiceProvider
    // Wrapper for:
    //{ provide: HeroService,
    //  useFactory: (logger: Logger, userService: UserService) => {
    //    return new HeroService(logger, userService.user.isAuthorized)
    //  },
    //  deps: [Logger, UserService]
    //};

  ],
  bootstrap: [ AppComponent ]
})

Notez que dans docs angulaires ici , heroServiceProvider est fourni dans heroes.component et non dans app.module, et les références à Logger et UserService ne sont pas nécessaires. Je suppose que ces deux dépendances sont en train d’être détectées plus haut dans l’arbre d’injection.

2
Richard Matsen

1) La première partie de votre question est simple: il vous suffit de conserver l'extrait de code que vous avez fourni dans un fichier séparé et de l'importer dans le composant, comme indiqué dans votre question:

import { heroServiceProvider } from './hero.service.provider';

2) En ce qui concerne l'utilisation réelle, vous n'avez pas vraiment besoin de changer le code lié au service dans le composant. Continuez simplement à l’utiliser si le service original a été injecté. Vous n'avez même pas besoin de modifier votre constructeur de composant. L'idée du fournisseur de services est que vous pouvez personnaliser votre service pour chaque composant en ayant un fournisseur de services personnalisé pour chaque composant, et vous effectueriez une initialisation spécifique à un composant dans la fonction d'usine. N'oubliez pas de nommer votre fournisseur de services dans le décorateur de votre composant, Angular s'occupe du reste "automatiquement".

1
Anton Nikiforov

Aujourd'hui, j'ai affronté la même question et trouvé une solution.

1) J'ai trouvé le code exact dans angular.io, voir ci-dessous: https://github.com/angular/angular.io/blob/master/public/docs/_examples/dependency-injection/ts/ src/app/heroes/hero.service.provider.ts (lien mis à jour le 15 mars 2017).
A partir de ce code, heroServiceProvider n’a pas besoin d’être une classe.

2) Dans app.module.ts, il existe une propriété de fournisseur dans @NgModule. Et vous pouvez ajouter heroServiceProvider dans les cas suivants:

import { heroServiceProvider } from './hero.service.provider';

...

@NgModule({

  ...

  providers: [
    heroServiceProvider
  ],
  bootstrap: [ AppComponent ]
})

En fournissant un service dans @NgModule comme cela, vous pouvez utiliser le service dans la portée de l'application.

0
mgmg