My goal is simple in principle, but I can not put it in place: I want one of my components to be updated when the variable of a service is changed.
To better explain my problem, here is an example :
Here, I have a service that increases or decreases a number of points. It decreases or increases this number of points when it receives a call to one of its functions. It also says if this variable is even or odd
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;
}
}
*Here, I have my component, which needs to know if my figure is even or odd.
At initialization, no problem! It knows it!
How, every time the number changes in my service (test.service.ts) then I make sure that the value pair/import changes in my component (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;
}
}
How should I do it ?
Did my component need to subscribe
to my service in some way?
Or Did I have to use one function like ngOnInit
but for update?
Thanks in advance
It would have automatically updated if these service variables were of a complex type like an Object or an Array as these are reference types. But since you have Service variables of type number and boolean, these will not be updated automatically as they are primitive types and hence passed by value.
So you'll have to use BehaviorSubject
s and expose them asObservable
s. You'll update the values of these BehaviorSubject
s by calling the next
method on them. Here's how:
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);
}
}
Now in your Component, all you need to do is subscribe
to the public
ly exposed Observable
values from the 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();
}
}
Now since you've subscribe
d to isOdd$
in ngOnInit
which gets called during component initialization, isOdd
on your Component will update every time there is a change in the isOddValue
in the service.
Also since this is a custom subscription
it should be assigned to a property in the Component(subscription
) which would be of type Subscription
which is what we get from the subscribe
method as a return value. We will have to call unsubscribe
on it in ngOnDestroy
to avoid memory leaks.
PS: Property and method names in Angular Classes should be in lowerCamelCase according to Angular's Styleguide.
Do use lower camel case to name properties and methods.
For what you are saying to work, you should be increasing/decreasing the number
in the service within the TestComponent, not in other components.
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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With