Обновление значения переменной в сервисе из нескольких компонентов

#angular #typescript

#angular #typescript

Вопрос:

У меня есть service DisplaysService, в котором есть переменная moneys . Когда я что-то покупаю с помощью компонента buy button on the buy, я обновляю значение переменной в сервисе из компонента. Однако обновленное значение не отражается в компоненте sell, даже если я получаю значение из сервиса. Значение, отображаемое в компоненте sell, является исходным значением переменной в сервисе DisplaysService.

displays.service.ts

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

    @Injectable({
      providedIn: 'root'
    })
    export class DisplaysService {
      moneys = 50000;

      constructor() { }
    }

  

buy.component.ts

 
    import { DisplaysService } from './../displays.service';
    import { Component, OnInit } from '@angular/core';
    import { HttpClient } from '@angular/common/http';

    @Component({
      selector: 'app-buy',
      templateUrl: './buy.component.html',
      styleUrls: ['./buy.component.css']
    })
    export class BuyComponent implements OnInit {
      moneys : number;
      Response = {};
      selectedcurrency : string = "Select Currency"

      constructor(private http : HttpClient, private displaysservice : DisplaysService) { }

      ngOnInit(): void {
        this.http.get('https://api.coinranking.com/v1/public/coins?base=EURamp;timePeriod=7d') 
        .subscribe(Response => { 
          console.log(Response)
          this.Response = Response 
        }); 
      }

      ChangeCurrencySymbol (newcurrency : string) { 
        this.selectedcurrency = newcurrency;
      }

      ChangeMoneys (moneysspent : Number) {
        this.moneys = this.displaysservice.moneys - Number(moneysspent);
        this.displaysservice.moneys = this.moneys;
      }
    }

  

sell.component.ts

 
    import { DisplaysService } from './../displays.service';
    import { Component, OnInit } from '@angular/core';
    import { HttpClient } from '@angular/common/http';

    @Component({
      selector: 'app-sell',
      templateUrl: './sell.component.html',
      styleUrls: ['./sell.component.css']
    })
    export class SellComponent implements OnInit {
      moneys : number;
      Response = {};
      selectedcurrency : string = "Select Currency"

      constructor(private http : HttpClient, private displaysservice : DisplaysService) { }

      ngOnInit(): void {
        this.http.get('https://api.coinranking.com/v1/public/coins?base=EURamp;timePeriod=7d') 
        .subscribe(Response => { 
          console.log(Response)
          this.Response = Response 
        }); 
      }

      ChangeCurrencySymbol (newcurrency : string) { 
        this.selectedcurrency = newcurrency;
      }

      ChangeMoneys (moneysspent : Number) {
        this.moneys = this.displaysservice.moneys   Number(moneysspent);
        this.displaysservice.moneys = this.moneys;
      }
    }

  

См. Ссылку на воспроизведение stackblitz

Комментарии:

1. Пробовал извлекать значение в ngOnInit() ??

Ответ №1:

Проблема

Angular пытается оптимизировать производительность, применяя изменения к пользовательскому интерфейсу, когда ожидается, что изменение обновит пользовательский интерфейс.

Рассмотрим приведенную ниже последовательность событий

  • Вы присваиваете свойству DisplayService: moneys значение 50,000.00
  • Вы присваиваете свойству BuyComponent: moneys значение DisplayService: moneys , теперь BuyComponent: moneys значение равно 50,000
  • Вы присваиваете свойству SellComponent: moneys значение DisplayService: moneys , теперь SellComponent: moneys значение равно 50,000
  • Теперь давайте обновим SellComponent: moneys , а затем обновим DisplayService: moneys
  • Теперь у нас проблема, компонент никак не BuyComponent мог знать об этом изменении

Решение

Простым подходом было бы установить значение DisplayService: moneys как a BehaviorSubject и подписаться на это как в компонентах Buy, так и в компонентах Sell . Таким образом, значение будет синхронизировано. Смотрите приведенный ниже код

displays.service.ts

   private readonly initialMoneys = 50000;
  moneysSubject$ = new BehaviorSubject(this.initialMoneys);
  moneys$ = this.moneysSubject$.asObservable();
  updateDisplay({ amount, type }) {
    if (type === "sell") {
      this.moneysSubject$.next(amount   this.moneys);
    }
    if (type === "buy") {
      this.moneysSubject$.next(-amount   this.moneys);
    }
  }
  get moneys() {
    return this.moneysSubject$.value;
  }
  

buy.component.ts

 export class BuyComponent implements OnInit {
  moneys$ = this.displaysservice.moneys$;
  Response = {};
  selectedcurrency: string = "Select Currency";

  constructor(
    private http: HttpClient,
    private displaysservice: DisplaysService
  ) {}

  ngOnInit(): void {
    this.http
      .get("https://api.coinranking.com/v1/public/coins?base=EURamp;timePeriod=7d")
      .subscribe(Response => {
        console.log(Response);
        this.Response = Response;
      });
  }

  ChangeCurrencySymbol(newcurrency: string) {
    this.selectedcurrency = newcurrency;
  }

  ChangeMoneys(moneysspent: number) {
    this.displaysservice.updateDisplay({ amount: moneysspent, type: "sell" });
  }
}
  

sell.component.ts

 export class SellComponent implements OnInit {
  moneys$ = this.displaysservice.moneys$;
  Response = {};
  selectedcurrency: string = "Select Currency";

  constructor(
    private http: HttpClient,
    private displaysservice: DisplaysService
  ) {}

  ngOnInit(): void {
    this.http
      .get("https://api.coinranking.com/v1/public/coins?base=EURamp;timePeriod=7d")
      .subscribe(Response => {
        console.log(Response);
        this.Response = Response;
      });
  }

  ChangeCurrencySymbol(newcurrency: string) {
    this.selectedcurrency = newcurrency;
  }

  ChangeMoneys(moneysspent: number) {
     this.displaysservice.updateDisplay({amount: moneysspent, type:'buy'});
  }
}
  

Смотрите Ссылку на демонстрацию stackblitz