Angular 6: Обновите значение в моем компоненте, когда она изменится в моем сервисе - PullRequest
0 голосов
/ 19 ноября 2018

Моя цель проста в принципе, но я не могу поставить ее на место: Я хочу, чтобы один из моих компонентов обновлялся при изменении переменной службы.

Комулучше объясните мою проблему, вот пример:

Здесь у меня есть услуга, которая увеличивает или уменьшает количество пунктов.Это количество очков уменьшается или увеличивается при получении вызова одной из его функций.В нем также указано, является ли эта переменная четной или нечетной

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

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

При инициализации, нет проблем!Он это знает!

Как, каждый раз, когда число изменяется в моем сервисе (test.service.ts), я проверяю, что пара значений / импорт изменяется в моем компоненте (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;
  }

}

Как мне это сделать?

Нужно ли было, чтобы мой компонент каким-то образом нуждался в subscribe для моей службы?Или я должен был использовать одну функцию, например ngOnInit, но для обновления?

Заранее спасибо

Ответы [ 4 ]

0 голосов
/ 17 марта 2019

Observable - отличный способ сделать это.

Другой простой способ, и, на мой взгляд, намного проще - генерировать событие всякий раз, когда в TestService.

вызываются методы IncreaseNumber или DecreaseNumber.

Затем в конструкторе вашего TestComponent вы можете подписаться на событие, созданное вами в TestService, а затем обновить свое поле IsOdd (или любое другое поле, которое вы хотите обновить в своем компоненте). Эта подписка возможна, потому что событие является оберткой для наблюдаемого.

Вроде так: Во-первых, создайте в вашем сервисе источник событий

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

Тогда подпишитесь на событие в конструкторе вашего компонента

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

Вот, пожалуйста, просто и эффективно.

0 голосов
/ 19 ноября 2018

Он бы автоматически обновлялся, если бы эти служебные переменные имели сложный тип, такой как Object или Array, поскольку они являются ссылочными типами. Но поскольку у вас есть служебные переменные типа number и boolean, они не будут обновляться автоматически, поскольку они являются примитивными типами и, следовательно, передаются по значению.

Так что вам придется использовать BehaviorSubject s и выставлять их asObservable s. Вы обновите значения этих BehaviorSubject s, вызвав для них метод next. Вот как это сделать:

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

Теперь в вашем Компоненте все, что вам нужно сделать, это subscribe до public значительных Observable значений из Службы:

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

}

Теперь, поскольку у вас subscribe d до isOdd$ в ngOnInit, который вызывается во время инициализации компонента, isOdd в вашем Компоненте будет обновляться каждый раз, когда происходит изменение в isOddValue в службе.

Также, поскольку это пользовательский subscription, его следует назначить свойству в Компоненте (subscription), которое будет иметь тип Subscription, что мы получаем из метода subscribe в качестве возвращаемого значения. , Мы должны вызвать unsubscribe на нем в ngOnDestroy, чтобы избежать утечек памяти.

PS: Имена свойств и методов в Angular Classes должны быть в lowerCamelCase в соответствии с Styleguide Angular .

Использовать нижний регистр верблюда для именования свойств и методов.

0 голосов
/ 19 ноября 2018

Существует несколько решений, которые вы можете использовать, включая настройку Observable для подписки на изменения. Это все действующие решения.

Самое простое решение - привязать сервис к шаблону, а не к значению:

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

В ngOnInit вы присваиваете логическое значение свойству компонента. Это значение никогда не меняется. Чтобы создать привязку данных и реагировать на изменения, необходимо привязать ссылку к свойству, используя объект, для которого требуется . Таким образом, MyService.IsOdd будет работать в шаблоне.

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

0 голосов
/ 19 ноября 2018

Для того, что вы говорите, вы должны увеличивать / уменьшать number в сервисе внутри TestComponent, а не в других компонентах.

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

}
...