Makina Blog

Le blog Makina-corpus

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

Image
Widget
04/04/2023

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.

Voir l'article
Image
Vue.js + D3.js, un bon combo !
30/03/2023

Vue.js & D3.js : un bon combo pour une data visualisation dynamique

Pour faire des indicateurs dynamiques avec D3.js, l'utilisation d'un framework front comme Vue.js peut simplifier la vie.

Voir l'article
Image
Drapeaux
12/01/2023

Afficher n'importe quel drapeau du monde avec flag-icons

J'ai récemment eu besoin d'implémenter un sélecteur de langue avec des drapeaux dans une application web. J'avais envie de trouver une manière rapide de le faire sans avoir à intégrer tous les drapeaux un par un, et de la manière la plus légère possible.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus