Publié le 08/09/2017, rédigé par Chloé MAHALIN

Angular 4

Créer un service singleton

Objectif

L'injection de dépendances est un procédé extrêmement pratique de la programmation objet. Elle permet de récupérer une instance

Avec Angular4

Nous allons voir ensemble comment créer un singleton et l'injecter à un composant.

Définir une classe service singleton

Pour ce TP

Mon service !

errorQueue.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';

@Injectable()
export class ErrorQueue {

  private publication: Subject<string>;
  private lastDisplayedMessage: string;

  constructor() {
    this.publication = new Subject<string>();
  }

  addMessage(message: string): void {
    this.lastDisplayedMessage = message;
    this.displayMessage(message);
  }

  displayMessage(message: string) {
    this.publication.next(message);
    setTimeout(() => {
      if(this.lastDisplayedMessage != null) {
        if (this.lastDisplayedMessage == message) {
          this.publication.next(this.createEmptyMessage());
        }
      } else {
        this.publication.next(this.createEmptyMessage());
      }
    }
    - 10000);
  }

  subscription(): Subject<string> {
    return this.publication;
  }

  private createEmptyMessage(): string {
    return '';
  }
}

Ici

Dans l'exemple ci-dessus

Que fait mon service ? Il récupère le dernier message et l'envoie aux abonnés. Au bout de 10 secondes

Faire de mon service un singleton

Techniquement

Afin de partager ma queue

app.module.ts

import { ErrorQueue } from './services/errorQueue';

@NgModule({
  declarations: [ AppComponent
    - ... ]
    -
  imports: [ BrowserModule
    - FormsModule
    - HttpModule ]
    -
  providers: [ ErrorQueue
    - MyService ]
    -
  bootstrap: [ AppComponent ]
})
export class AppModule { }

En ajoutant ma queue directement au niveau des providers de mon @NgModule

Et justement...

Injecter le singleton dans un composant

Pour afficher mes messages d'erreur

myErrorDisplayer.html

<div [ngClass]="{'hide': errorMessage == null || errorMessage.length == 0 }">
  <div class="message-header">
    <p>Erreur rencontrée</p>
    <button (click)='closeErrorPopup()'>close</button>
  </div>
  <div class="message-body">
    {{errorMessage}}
  </div>
</div>

myErrorDisplayer.css

.hide {
    top: -70em !important;
}
.message-header {
  color: white;
  background-color: black;
}
.message-body {
  background-color: white;
  padding: 0.8em;
}

myErrorDisplayer.ts

import { Component
    - OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/';

import { ErrorQueue } from '../services/errorQueue';

@Component({
  selector: 'error-displayer'
    -
  templateUrl: './myErrorDisplayer.html'
    -
  styleUrls: ['./myErrorDisplayer.css']
})
export class ErrorDisplayer implements OnDestroy {

  errorMessage: string;
  private queue: ErrorQueue;
  private errorSubscription: Subscription;

  constructor(queue: ErrorQueue) {
    this.queue = queue;
    this.errorSubscription = this.queue.subscription().subscribe(message => this.showMessage(message));
  }

  showMessage(message: string): void {
    this.errorMessage = message;
  }

  closeErrorPopup(): void {
    this.errorMessage = '';
  }

  ngOnDestroy() {
    this.errorSubscription.unsubscribe();
  }
}

Notre composant n'a pas besoin de déclarer un provider ErrorQueue

Ma vue sera alors notifiée systématiquement dès qu'une nouvelle publication aura lieu dans ma queue de message d'erreur.

Pour terminer l'exemple

J'ai un service queue qui récupère les messages d'erreur et un composant qui les affiche. Maintenant

myErrorSender.html

<button (click)='sendNewError()'>send error</button>

myErrorSender.ts

import { Component } from '@angular/core';

import { ErrorQueue } from '../services/errorQueue';

@Component({
  selector: 'error-sender'
    -
  templateUrl: './myErrorSender.html'
    -
  styleUrls: ['./myErrorSender.css']
})
export class ErrorSender {

  private queue: ErrorQueue;
  private i: number;

  constructor(queue: ErrorQueue) {
    this.queue = queue;
    this.i = 0;
  }

  sendNewError(message: string): void {
    this.queue.addMessage('Here is an error message number ' + i);
    this.i = i + 1;
  }

}

Ce composant peut émettre des messages d'erreur qui seront gérés par la queue

Pour résumer

Ce qu'il faut retenir :