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
Symfony + Vue.js
21/06/2022 - 15:02

Créer une application Symfony/Vue.js

Pour faire des essais ou bien démarrer un nouveau projet, vous avez besoin de créer rapidement une application Symfony couplée avec un front Vue.js ? Suivez le guide !

Voir l'article
Image
Logo Cypress
11/10/2021 - 16:38

Retour d’expérience : tests fonctionnels avec Cypress

Dans le cadre d'un de nos projets de développement spécifique, l’équipe Makina Corpus a été amenée à coder un important logiciel métier avec de nombreuses entités et règles de gestion : l’Hydroportail.

Voir l'article
29/03/2019 - 15:28

Des boucles de composants génériques avec Angular

Ou comment faire des composants de listes réutilisables avec n'importe quel objet.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus