Mon objectif est simple en principe, mais je ne peux pas le mettre en place: Je souhaite qu'un de mes composants soit mis à jour lorsque la variable d'un service est modifiée.

Pour mieux expliquer mon problème, voici un exemple:

Ici, j'ai un service qui augmente ou diminue un nombre de points. Il diminue ou augmente ce nombre de points lorsqu'il reçoit un appel à l'une de ses fonctions. Il indique également si cette variable est paire ou impaire

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

@Injectable({
  providedIn: 'root'
})
export class TestService {
  Number: number = 0;
  IsOdd: boolean = false;

  constructor() {}

  IncreaseNumber() {
    this.Number = this.Number + 1;
    this.IsOdd = !this.IsOdd;
  }

  DecreaseNumber() {
    this.Number = this.Number - 1;
    this.IsOdd = !this.IsOdd;
  }
}

* Ici, j'ai mon composant, qui a besoin de savoir si mon chiffre est pair ou impair.

A l'initialisation, pas de problème! Il le sait!

Comment, à chaque fois que le numéro change dans mon service (test.service.ts), je m'assure que la valeur paire / import change dans mon composant (test.component.ts)? *

import { Component, OnInit } from '@angular/core';
import { TestService } from '../test.service'

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss']
})

export class TestComponent implements OnInit {

  IsOdd: boolean = false;

  constructor(MyService: TestService) {}

  ngOnInit() {
    this.IsOdd = MyService.IsOdd;
  }

}

Comment dois-je procéder?

Mon composant devait-il subscribe accéder à mon service d'une manière ou d'une autre? Ou Dois-je utiliser une fonction comme ngOnInit mais pour la mise à jour?

Merci d'avance

5
Scieur Arnaud 19 nov. 2018 à 18:35

4 réponses

Meilleure réponse

Il se serait automatiquement mis à jour si ces variables de service étaient d'un type complexe comme un objet ou un tableau, car ce sont des types de référence. Mais comme vous avez des variables de service de type number et boolean, celles-ci ne seront pas mises à jour automatiquement car ce sont des types primitifs et donc passées par valeur.

Vous devrez donc utiliser des BehaviorSubject et les exposer asObservable. Vous allez mettre à jour les valeurs de ces BehaviorSubject en appelant la méthode next sur eux. Voici comment:

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

@Injectable({
  providedIn: 'root'
})
export class TestService {
  private myNumberValue = 0;
  private isOddValue = false;
  private myNumber: BehaviorSubject<number> = new BehaviorSubject<number>(this.myNumberValue);
  private isOdd: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

  myNumber$: Observable<number> = this.myNumber.asObservable();
  isOdd$:  Observable<boolean> = this.isOdd.asObservable();

  constructor() {}

  increaseNumber() {
    this.myNumberValue = this.myNumberValue + 1;
    this.myNumber.next(this.myNumberValue);
    this.isOddValue = !this.isOddValue;
    this.isOdd.next(this.isOddValue);
  }

  decreaseNumber() {
    this.myNumberValue = this.myNumberValue - 1;
    this.myNumber.next(this.myNumberValue);
    this.isOddValue = !this.isOddValue;
    this.isOdd.next(this.isOddValue);
  }
}

Maintenant dans votre composant, tout ce que vous avez à faire est de subscribe aux valeurs public exposées Observable du service:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { TestService } from '../test.service'
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss']
})

export class TestComponent implements OnInit, OnDestroy {

  isOdd: boolean;
  subscription: Subscription;

  constructor(private testService: TestService) {}

  ngOnInit() {
    this.subscription = this.testService.isOdd$.subscribe(isOdd => this.isOdd = isOdd);
  }

  ngOnDestroy() {
    this.subscription && this.subscription.unsubscribe();
  }

}

Maintenant que vous avez subscribe d à isOdd$ dans ngOnInit qui est appelé lors de l'initialisation du composant, isOdd sur votre composant sera mis à jour chaque fois qu'il y aura un changement dans le {{ X4}} dans le service.

De plus, comme il s'agit d'un subscription personnalisé, il devrait être attribué à une propriété du composant (subscription) qui serait de type Subscription, ce que nous obtenons du subscribe méthode comme valeur de retour. Nous devrons appeler unsubscribe dessus dans ngOnDestroy pour éviter les fuites de mémoire.

PS: Les noms de propriété et de méthode dans les classes angulaires doivent être dans lowerCamelCase selon Guide de style Angular .

Utilisez la casse inférieure du chameau pour nommer les propriétés et les méthodes.

4
SiddAjmera 19 nov. 2018 à 16:19

Pour que ce que vous dites fonctionne, vous devez augmenter / diminuer le number dans le service au sein du TestComponent, pas dans les autres composants.

import { Component, OnInit } from '@angular/core';
import { TestService } from '../test.service'

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss']
})

export class TestComponent implements OnInit {

  IsOdd: boolean = false;

  constructor(MyService: TestService) {}

  ngOnInit() {
    this.IsOdd = MyService.IsOdd;
  }

  increase() {
    MyService.IncreaseNumber();
  }

  decrease() {
    MyService.DecreaseNumber();
  }

  getIsOdd() {
    return MyService.IsOdd;
  }

}
1
gatsbyz 19 nov. 2018 à 15:48

Il existe plusieurs solutions que vous pouvez utiliser, notamment la configuration d'un observable pour vous abonner aux modifications. Ce sont toutes des solutions valables.

La solution la plus simple serait de se lier au service dans le modèle plutôt qu'à la valeur:

<div> {{ MyService.IsOdd }} </div>

Dans ngOnInit, vous affectez la valeur booléenne à une propriété du composant. Cette valeur ne change jamais. Afin de créer une liaison de données et de répondre aux modifications, vous devez lier une référence à une propriété en utilisant un objet qui nécessite un .. Ainsi, le MyService.IsOdd fonctionnera dans le modèle.

https://stackblitz.com/edit/angular-rktij7

1
Explosion Pills 19 nov. 2018 à 15:53

Observable est un excellent moyen de le faire.

Un autre moyen simple et à mon avis beaucoup plus simple est d'émettre un événement chaque fois que les méthodes IncreaseNumber ou DecreaseNumber sont appelées dans le TestService.

Ensuite, dans le constructeur de votre TestComponent, vous pouvez vous abonner à l'événement que vous avez créé dans le TestService puis mettre à jour votre champ IsOdd (ou tout autre champ que vous souhaitez mettre à jour dans votre composant). Cet abonnement est possible car un événement est un wrapper pour observable.

Comme ça: Tout d'abord, créez un émetteur d'événements dans votre service

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

    @Injectable({
      providedIn: 'root'
    })
    export class TestService {
      Number: number = 0;
      IsOdd: boolean = false;
      EmitIsOdd = new EventEmitter<any>();

      constructor() {}

      IncreaseNumber() {
        this.Number = this.Number + 1;
        this.IsOdd = !this.IsOdd;
        this.EmitIsOdd.emit();
      }

      DecreaseNumber() {
        this.Number = this.Number - 1;
        this.IsOdd = !this.IsOdd;
        this.EmitIsOdd.emit();
      }
    }

Ensuite, inscrivez-vous à l'événement dans votre constructeur de composants

    import { Component, OnInit } from '@angular/core';
    import { TestService } from '../test.service'

    @Component({
      selector: 'app-test',
      templateUrl: './test.component.html',
      styleUrls: ['./test.component.scss']
    })

    export class TestComponent implements OnInit {

      IsOdd: boolean = false;

      constructor(MyService: TestService) {
        this.MyService.EmitIsOdd.subscribe(
          () => {
            this.IsOdd = this.MyService.IsOdd;
          }    
        );
      }

      ngOnInit() {
        this.IsOdd = MyService.IsOdd;
      }
    }

Voilà, simple et efficace.

0
Onome Sotu 17 mars 2019 à 04:11