J'ai lu que l'injection lors du démarrage devrait avoir tous les enfants partager la même instance, mais mes composants principaux et d'en-tête (l'application principale comprend le composant d'en-tête et la sortie de routeur) reçoivent chacun une instance distincte de mes services.
J'ai un FacebookService que j'utilise pour passer des appels vers l'API javascript facebook et un UserService qui utilise le FacebookService. Voici mon bootstrap:
bootstrap(MainAppComponent, [ROUTER_PROVIDERS, UserService, FacebookService]);
D'après ma journalisation, il semble que l'appel de démarrage se termine, puis je vois le FacebookService puis UserService en cours de création avant que le code de chacun des constructeurs ne s'exécute, le MainAppComponent, le HeaderComponent et le DefaultComponent:
angular
typescript
angular2-routing
angular2-services
Jason Goemaat
la source
la source
UserService
etFacebookService
àproviders
nulle part ailleurs?Réponses:
Jason a tout à fait raison! Cela est dû au fonctionnement de l'injection de dépendances. Il est basé sur des injecteurs hiérarchiques.
Il existe plusieurs injecteurs dans une application Angular2:
Quand Angular2 essaie d'injecter quelque chose dans le constructeur du composant:
Donc, si vous souhaitez avoir un singleton pour l'ensemble de l'application, vous devez définir le fournisseur au niveau de l'injecteur racine ou de l'injecteur de composant d'application.
Mais Angular2 examinera l'arborescence des injecteurs par le bas. Cela signifie que le fournisseur au niveau le plus bas sera utilisé et la portée de l'instance associée sera ce niveau.
Voir cette question pour plus de détails:
la source
Mise à jour (Angular 6 +)
La méthode recommandée pour créer un service singleton a changé. Il est maintenant recommandé de spécifier dans le
@Injectable
décorateur sur le service qu'il doit être fourni dans la 'racine'. Cela a beaucoup de sens pour moi et il n'est plus du tout nécessaire de lister tous les services fournis dans vos modules. Vous importez simplement les services lorsque vous en avez besoin et ils s'enregistrent au bon endroit. Vous pouvez également spécifier un module afin qu'il ne soit fourni que si le module est importé.Mise à jour (Angular 2)
Avec NgModule, la façon de le faire maintenant, je pense, est de créer un 'CoreModule' avec votre classe de service à l'intérieur et de répertorier le service dans les fournisseurs du module. Ensuite, vous importez le module de base dans votre module d'application principal qui fournira une instance à tous les enfants qui demandent cette classe dans leurs constructeurs:
CoreModule.ts
AppModule.ts
Réponse originale
Si vous répertoriez un fournisseur dans
bootstrap()
, vous n'avez pas besoin de le répertorier dans votre décorateur de composants:En fait, lister votre classe dans «fournisseurs» crée une nouvelle instance de celle-ci, si un composant parent la répertorie déjà, les enfants n'en ont pas besoin, et s'ils le font, ils obtiendront une nouvelle instance.
la source
[providers]
dans votre fichier de module, pas dansbootstrap()
, non?ApiService
dansAppModule
« sproviders
, et éviter ainsi la nécessité d' uneCoreModule
? (Je ne suis pas sûr que ce soit ce que suggère @JasonSwett.)ApiService
dessus, mais pourquoi se donner la peine de le mettre dans le tableau des fournisseurs du CoreModule, puis importer celui-ci dans app.module ... il n'a pas encore cliqué pour moi.TestService
est spécifiée à la fois dans les modules principaux et dans les modules d'application, les instances ne sont pas créées pour les modules car elles sont fournies par le composant de sorte que angulaire ne monte jamais aussi haut dans l'arborescence des injecteurs. Donc, si vous fournissez un service dans votre module et que vous ne l'utilisez jamais, une instance ne semble pas être créée.Je sais qu'angular a des injecteurs hiérarchiques comme l'a dit Thierry.
Mais j'ai une autre option ici au cas où vous trouveriez un cas d'utilisation où vous ne voudriez pas vraiment l'injecter au parent.
Nous pouvons y parvenir en créant une instance du service, et en fournissant toujours cela.
Et puis sur votre composant, vous utilisez votre méthode de fourniture personnalisée.
Et vous devriez avoir un service singleton sans dépendre des injecteurs hiérarchiques.
Je ne dis pas que c'est une meilleure façon, c'est juste au cas où quelqu'un aurait un problème où les injecteurs hiérarchiques ne sont pas possibles.
la source
SHARE_SERVICE_PROVIDER
êtreYOUR_SERVICE_PROVIDER
dans le composant? De plus, je suppose que l'importation du fichier de service est nécessaire comme d'habitude et que le constructeur aura toujours un paramètre de type «YourService», non? J'aime cela, je pense, vous permet de garantir un singleton et de ne pas avoir à vous assurer que le service est fourni dans la hiérarchie. Cela permet également aux composants individuels d'obtenir leur propre copie en répertoriant simplement le service auproviders
lieu du fournisseur singleton, n'est-ce pas?YOUR_SERVICE_PROVIDER
. Oui, tous les composants obtiendront la même instance en l'ajoutant simplement dans les fournisseurs.instance
propriété en une carte d'instances clé-valeurLa syntaxe a été modifiée. Vérifiez ce lien
Les dépendances sont des singletons dans le cadre d'un injecteur. Dans l'exemple ci-dessous, une seule instance de HeroService est partagée entre HeroesComponent et ses enfants HeroListComponent.
Étape 1. Créez une classe singleton avec le décorateur @Injectable
Étape 2. Injecter dans le constructeur
Étape 3. Enregistrer le fournisseur
la source
Injectable
classe n'est pas un service et contient juste desstatic
chaînes pour une utilisation globale?L'ajout d'un
@Injectable
décorateur au service ET son enregistrement en tant que fournisseur dans le module racine en fera un singleton.la source
constructor
suivante:import { SomeService } from '../../services/some/some'; @Component({ selector: 'page-selector', templateUrl: 'page.html', }) export class SomePage { constructor( public someService: SomeService ) { }
cela semble bien fonctionner pour moi
la source
Voici un exemple de travail avec Angular version 2.3. Appelez simplement le constructeur du service à la manière de ce constructeur (private _userService: UserService). Et cela créera un singleton pour l'application.
user.service.ts
app.component.ts
la source
A
singleton service
est un service pour lequel une seule instance existe dans une application.Il existe (2) façons de fournir un service singleton pour votre application.
utiliser la
providedIn
propriété, oufournir le module directement dans le
AppModule
de l'applicationUtilisation de providedIn
À partir d'Angular 6.0, la meilleure façon de créer un service singleton est de définir la
providedIn
racine sur le@Injectable()
décorateur du service . Cela indique à Angular de fournir le service à la racine de l'application.Tableau des fournisseurs NgModule
Dans les applications créées avec des versions Angular antérieures à 6.0, les services sont des tableaux de fournisseurs NgModule enregistrés comme suit:
S'il
NgModule
s'agissait de la racineAppModule
, le UserService serait un singleton et disponible dans toute l'application. Bien que vous puissiez le voir codé de cette façon, utiliser laprovidedIn
propriété du@Injectable()
décorateur sur le service lui-même est préférable à partir d'Angular 6.0 car cela rend vos services transformables en arborescence.la source
Vous pouvez utiliser
useValue
dans les fournisseursla source
useValue
n'est pas lié au singleton. Usevalue est juste de passer une valeur au lieu d'unType
(useClass
) que DI appellenew
ouuseFactory
où une fonction est passée qui retourne la valeur lorsqu'elle est appelée par DI. Angular DI gère automatiquement une seule instance par fournisseur. Ne le fournissez qu'une seule fois et vous avez un singleton. Désolé, je dois voter contre car ce n'est qu'une information invalide: - /Depuis Angular @ 6, vous pouvez avoir
providedIn
dans un fichierInjectable
.Consultez les documents ici
la source
public static
.Déclarez simplement votre service en tant que fournisseur dans app.module.ts uniquement.
Cela a fait le travail pour moi.
puis instanciez-le en utilisant un paramètre privé du constructeur:
ou puisque si votre service est utilisé à partir de html, l'option -prod réclamera:
ajoutez un membre pour votre service et remplissez-le avec l'instance reçue dans le constructeur:
la source
Si vous souhaitez rendre le service singleton au niveau de l'application, vous devez le définir dans app.module.ts
fournisseurs: [MyApplicationService] (vous pouvez également définir la même chose dans le module enfant pour le rendre spécifique à ce module)
Si vous souhaitez définir un service singleton au niveau du service de création de composant, ajoutez ce service dans app.module.ts et ajoutez un tableau de fournisseurs à l'intérieur d'un composant spécifique, comme indiqué dans l'extrait ci-dessous.
@Component ({selector: 'app-root', templateUrl: './test.component.html', styleUrls: ['./test.component.scss'], fournisseurs: [TestMyService]})
Angular 6 fournit une nouvelle façon d'ajouter un service au niveau de l'application. Au lieu d'ajouter une classe de service au tableau des fournisseurs [] dans AppModule, vous pouvez définir la configuration suivante dans @Injectable ():
@Injectable ({providedIn: 'root'}) classe d'exportation MyService {...}
La "nouvelle syntaxe" offre cependant un avantage: les services peuvent être chargés paresseusement par Angular (dans les coulisses) et le code redondant peut être supprimé automatiquement. Cela peut améliorer les performances et la vitesse de chargement - bien que cela ne s'applique vraiment qu'aux services et applications plus volumineux en général.
la source
En plus des excellentes réponses ci-dessus, il peut y avoir quelque chose qui manque si les éléments de votre singleton ne se comportent toujours pas comme un singleton. J'ai rencontré le problème en appelant une fonction publique sur le singleton et en constatant qu'elle utilisait les mauvaises variables. Il s'avère que le problème était qu'il n'était
this
pas garanti d'être lié au singleton pour les fonctions publiques du singleton. Cela peut être corrigé en suivant les conseils ici , comme ceci:Alternativement, vous pouvez simplement déclarer les membres de la classe comme
public static
au lieu depublic
, alors le contexte n'aura pas d'importance, mais vous devrez y accéder commeSubscriptableService.onServiceRequested$
au lieu d'utiliser l'injection de dépendances et d'y accéder viathis.subscriptableService.onServiceRequested$
.la source
Services aux parents et aux enfants
J'avais des problèmes avec un service parental et son enfant utilisant des instances différentes. Pour forcer l'utilisation d'une instance, vous pouvez alias le parent en référence à l'enfant dans vos fournisseurs de modules d'application. Le parent ne pourra pas accéder aux propriétés de l'enfant, mais la même instance sera utilisée pour les deux services. https://angular.io/guide/dependency-injection-providers#alias-class-providers
app.module.ts
Services utilisés par les composants en dehors de la portée des modules de votre application
Lors de la création d'une bibliothèque composée d'un composant et d'un service, j'ai rencontré un problème où deux instances seraient créées. Un par mon projet Angular et un par le composant à l'intérieur de ma bibliothèque. Le correctif:
my-outside.component.ts
my-inside.component.ts
my-inside.component.hmtl
la source