typescript - Angular 6: Actualizează o valoare în componenta mea când se schimbă în serviciul meu


Scopul meu este simplu în principiu, dar nu îl pot pune în aplicare: Vreau ca unul dintre componentele mele să fie actualizat atunci când variabila unui serviciu se schimbă.

Pentru a-mi explica mai bine problema, iata un exemplu :

Aici, am un serviciu care mărește sau scade un număr de puncte. Scade sau mărește acest număr de puncte atunci când primește un apel la una dintre funcțiile sale. De asemenea, spune dacă această variabilă este pară sau impară

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;
  }
}

*Aici, am componenta mea, care trebuie să știe dacă cifra mea este pară sau impară.

La inițializare, nicio problemă! Știe asta!

Cum, de fiecare dată când numărul se schimbă în serviciul meu (test.service.ts), mă asigur că perechea de valori/importul se schimbă în componenta mea (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;
  }

}

Cum ar trebui să fac asta?

Componenta mea trebuia să se aboneze la serviciul meu într-un anumit fel? Sau trebuia să folosesc o funcție precum ngOnInit, dar pentru actualizare?

Mulțumesc anticipat

Răspuns #1

S-ar fi actualizat automat dacă aceste variabile de serviciu ar fi fost de un tip complex, precum un Obiect sau un Array, deoarece acestea sunt tipuri de referință. Dar, deoarece ai variabile de serviciu de tip număr și boolean, acestea nu vor fi actualizate automat, deoarece sunt tipuri primitive și, prin urmare, trecute prin valoare.

Deci va trebui să folosești BehaviorSubject-uri și să le expui ca asObservable-uri. Vei actualiza valorile acestor BehaviorSubject-uri apelând metoda next pe ele. Iată cum:

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);
  }
}

Acum, în Componenta ta, tot ce trebuie să faci este să te abonați la valorile Observable expuse public din 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();
  }

}

Acum, deoarece v-ați abonat la isOdd$ în ngOnInit, care este apelat în timpul inițializării componentului, isOdd din componenta dvs. se va actualiza de fiecare dată când există o schimbare în isOddValue din serviciu.

De asemenea, deoarece aceasta este o subscription personalizată, ar trebui să fie atribuită unei proprietăți în Component(subscription) care ar fi de tip Subscription, care este ceea ce obținem din metoda subscribe ca valoare de returnare. Va trebui să apelăm unsubscribe pe aceasta în ngOnDestroy pentru a evita scurgerile de memorie.

PS: Numele proprietăților și metodelor din clasele Angular ar trebui să fie în lowerCamelCase conform Ghidului de stil Angular.

Folosește camel case cu literă mică la început pentru a denumi proprietățile și metodele.

Răspunsul #2

Pentru ca ceea ce spui să funcționeze, ar trebui să mărești/micsorezi number în serviciu din cadrul TestComponent, nu în alte componente.

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;
  }

}