Les services sont des morceaux de code réutilisables que vous pouvez partager dans votre application Angular. Vous les utilisez généralement pour gérer la récupération de données, la logique métier ou d'autres fonctionnalités auxquelles plusieurs composants doivent accéder.
Créer un service
Vous pouvez créer un service avec l'Angular CLI à l'aide de la commande suivante :
ng generate service CUSTOM_NAME
Cette commande crée un fichier dédié CUSTOM_NAME.ts dans votre répertoire src.
Vous pouvez aussi créer un service manuellement en ajoutant le décorateur @Service() à une classe TypeScript. Cela indique à Angular que vous pouvez utiliser la classe comme une dépendance injectable.
L'exemple suivant définit un service qui permet aux utilisateurs d'ajouter et de récupérer des données :
src/app/basic-data-store.ts
import {Service} from '@angular/core';
@Service()
export class BasicDataStore {
private data: string[] = [];
addData(item: string): void {
this.data.push(item);
}
getData(): string[] {
return [...this.data];
}
}
Comment les services deviennent disponibles
Par défaut, les services sont fournis au niveau racine. Quand un service est fourni globalement, Angular garantit trois avantages principaux :
- Instance singleton : une seule instance partagée est créée pour toute l'application.
- Disponibilité globale : le service est automatiquement accessible partout, sans enregistrement manuel de provider.
- Tree-shaking : le service est exclu du bundle de production final si votre code ne l'utilise jamais explicitement.
Utiliser le décorateur @Service ou @Injectable
Le décorateur @Service est un raccourci moderne et ergonomique pour la syntaxe traditionnelle @Injectable({ providedIn: 'root' }).
Utilisez ce tableau récapitulatif pour choisir le décorateur adapté à votre situation :
| Fonctionnalité / besoin | @Service |
@Injectable |
|---|---|---|
Prise en charge de la fonction inject() |
Oui | Oui |
| DI par le constructeur | ❌ Non | Oui |
| Provider singleton racine implicite | Oui | ❌ Non (nécessite {providedIn: 'root'}) |
Clés de provider avancées (useClass, etc.) |
❌ Non | Oui |
| Fabriques d'initialisation personnalisées | Oui | Oui |
Portées autres que root (platform, etc.) |
❌ Non | Oui |
Remplacer l'implémentation par une fabrique
Si vous devez contrôler la façon dont le singleton est créé, par exemple pour utiliser une autre implémentation selon l'environnement, passez une fonction factory.
La fabrique s'exécute dans un contexte d'injection : vous pouvez donc y utiliser inject() pour lire d'autres dépendances.
Le service Analytics suivant ne fait rien en local, pour que les événements ne polluent pas la console pendant le développement. En production, la fabrique lit un jeton ANALYTICS_ENABLED et renvoie une sous-classe GoogleAnalytics qui transmet les événements au véritable outil de suivi :
src/app/analytics.ts
import {inject, InjectionToken, Service} from '@angular/core';
import {ANALYTICS_ENABLED} from './token';
@Service({
factory: () => (inject(ANALYTICS_ENABLED) ? new GoogleAnalytics() : new Analytics()),
})
export class Analytics {
track(event: string, payload?: Record<string, unknown>) {
// No-op by default.
}
}
class GoogleAnalytics extends Analytics {
override track(event: string, payload?: Record<string, unknown>) {
// Dispatches an analytics event to Google Analytics
}
}
Note : L'option factory remplace les options useClass, useValue, useExisting et useFactory de @Injectable. Si vous avez besoin de l'une d'elles, continuez à utiliser @Injectable.
Désactiver la fourniture automatique
Par défaut, @Service fournit la classe dans l'injector racine. Si vous voulez la fournir manuellement, par exemple pour limiter sa portée à une route ou à un composant précis, définissez autoProvided: false :
src/app/analytics-logger.ts
import {Service} from '@angular/core';
@Service({autoProvided: false})
export class AnalyticsLogger {
trackEvent(name: string) {
console.log('event:', name);
}
}
Il vous appartient alors d'ajouter le service à un tableau providers, comme avec un simple @Injectable() :
Quand utiliser @Service ou @Injectable
Optez pour @Service quand vous créez une nouvelle classe singleton qui utilise inject() pour ses dépendances. Continuez à utiliser @Injectable quand vous avez besoin de l'un des éléments suivants :
- L'injection de dépendances par le constructeur.
@Servicene prend en charge que la fonctioninject(). - Une configuration avancée du provider, comme
useClass,useValue,useExistingouuseFactory.@Serviceexpose à la place une seule optionfactory. - Des portées autres que root, comme
providedIn: 'platform'.
Injecter un service
Une fois que vous avez créé un service avec providedIn: 'root', vous pouvez l'injecter n'importe où dans votre application avec la fonction inject() de @angular/core.
Injecter dans un composant
import {Component, inject} from '@angular/core';
import {BasicDataStore} from './basic-data-store';
@Component({
selector: 'app-example',
template: `
<div>
<p>{{ dataStore.getData() }}</p>
<button (click)="dataStore.addData('More data')">Add more data</button>
</div>
`,
})
export class Example {
dataStore = inject(BasicDataStore);
}
Injecter dans un autre service
import {inject, Service} from '@angular/core';
import {AdvancedDataStore} from './advanced-data-store';
@Service()
export class BasicDataStore {
private advancedDataStore = inject(AdvancedDataStore);
private data: string[] = [];
addData(item: string): void {
this.data.push(item);
}
getData(): string[] {
return [...this.data, ...this.advancedDataStore.getData()];
}
}
Prochaines étapes
Si providedIn: 'root' couvre la plupart des cas d'usage, Angular propose aussi d'autres façons de configurer les services pour des scénarios plus spécialisés :
- Instances propres à un composant - quand des composants ont besoin de leurs propres instances isolées d'un service
- Configuration manuelle - pour les services qui nécessitent une configuration à l'exécution
- Providers de fabrique - pour créer dynamiquement des services selon des conditions d'exécution
- Providers de valeur - pour fournir des objets de configuration ou des constantes
Vous pouvez en apprendre davantage sur ces patterns avancés dans le guide suivant : définir des providers de dépendances.