Makina Blog
Physiologie et mœurs des services Angular 2
Sont-ils des singletons ? Faut-il éviter de les nourrir après minuit ?
Que sont les services Angular 2 ?
Entre Angular 1 et Angular 2, beaucoup de choses ont changé (on en a tous entendu parlé, les débats ont été nourris et ont parfois viré à la paranoïa), mais un des concepts qui a été conservé est celui de service.
Le cas d'usage reste le même : quand plusieurs composants ont besoin de faire la même chose, on va factoriser le code correspondant dans un service qui sera injecté dans chaque composant.
Créer un service
La déclaration est très simple (ci-dessous en TypeScript).
import {Injectable} from '@angular/core';
@Injectable()
export class LoginService {
constructor() {}
doSomething() {}
}
Injecter un service
Pour injecter notre service dans un composant, la syntaxe est la suivante:
import {Component} from '@angular/core';
import {LoginService} from 'login.service';
@Component({
selector: 'my-component',
providers: [LoginService],
template: require('./my.component.html')
})
export class MyComponent {
constructor(private loginService: LoginService) { }
ngOnInit() {
this.loginService.doSomething();
}
}
- premièrement, on importe notre service (ici on imagine qu'il est dans un fichier nommé `login.service.ts`),
- deuxièment, on le déclare dans les
providers
, - ensuite, on l'ajoute dans la signature du constructeur en tant que propriété privée,
- dès lors, on peut s'en servir dans les méthodes du composant via cette propriété (c'est-à-dire
this.monService
).
Note: attention, il faut toujours mettre les propriétés privées avant les propriétés publiques dans la signature.
Ok pour la syntaxe, mais que signifie-t-elle ?
Qui instancie le service ?
On voit que pour obtenir notre service, on a besoin de 2 déclarations : dans providers
et dans le constructeur.
Celle du constructeur ne fait qu'obtenir une instance du service au moment où le composant est créé.
Et c'est celle de providers
qui va effectivement instancier le service. En fait la notation :
providers: [LoginService]
est en fait une version abbrégée de :
[new Provider(LoginService, {useClass: LoginService})]
et cet objet Provider
est celui qui instancie le service et le donne au mécanisme d'injection qui le fournira au constructeur du composant.
Et avec plusieurs composants ?
Si plusieurs composants doivent utiliser le même service (et c'est souvent le cas), en général, on souhaite que le service soit un singleton, car il va sûrement stocker des données qu'on souhaite faire passer d'un composant à un autre (et puis de manière générale, on ne souhaite pas créer des objets nouveaux pour rien si on en a déjà un qui peut faire tout le travail).
Il ne faut donc pas le déclarer à chaque fois dans providers
, sinon nous aurons une nouvelle instance pour chaque composants.
D'accord, mais alors quel composant sera responsable d'instancier le service pour tout le monde ?
Tout simplement le composant le plus haut dans l'arbre de l'application. Si un composant A contient un composant B et que tous les deux utilisent le même service, c'est le composant A qui va le mentionner dans providers
, alors que le composant B se contentera de le mentionner uniquement dans la signature de son constructeur:
import {Component} from '@angular/core';
import {LoginService} from 'login.service';
@Component({
selector: 'my-sub-component',
template: require('./my.subcomponent.html')
})
export class MySubComponent {
constructor(private loginService: LoginService) { }
ngOnInit() {
this.loginService.doSomething();
}
}
Le système d'injection, voyant que le composant B ne fournit pas le service escompté, va regarder s'il est fourni par le composant père (le composant A), et si c'est le cas, en obtenir l'instance et la donner à B. Si ce n'est pas le cas, il va continuer à remonter l'arbre d'injection (en allant voir le père de A, puis son père à lui, etc., jusqu'à arriver à la racine de l'application).
Bien souvent ce sera d'ailleurs la racine de l'application elle-même qui va déclarer l'essentiel des services, non pas pour s'en servir directement, mais simplement pour qu'ils soient disponibles partout.
Alors singleton ou pas ?
On a donc le choix, tout service peut être un singleton ou pas, il suffit de gérer correctement nos providers
. Et un service non-singleton n'est pas forcément absurde d'ailleurs (les cas sont plus rares mais tout à fait valables).
Actualités en lien
Générer un fichier PMTiles avec Tippecanoe
Exemple de génération et d’affichage d’un jeu de tuiles vectorielles en PMTiles à partir de données publiques.
Publier une documentation VitePress sur Read The Docs
À l'origine, le site de documentation Read The Docs n'acceptait que les documentations Sphinx ou MKDocs. Depuis peu, le site laisse les mains libres pour builder sa documentation avec l'outil de son choix. Voici un exemple avec VitePress.
Créer une application en tant que composant web avec Stencil
Mise en place dans le cadre de Geotrek, cette solution permet de se passer d'une iFrame pour afficher une application dans n'importe quel site.