component1.html :
<div>
{{nums}}
</div>
TS:
nums: Array<number> = [0, 1, 2, 3];
ngOnInit(): void {
this.numService.getNum().subscribe((res) => {
this.num = res;
});
}
component2.html:
<div (click)="addNum()">
Add
</div>
TS:
addNum(): void {
this.numService.addNum(6);
}
NumService:
public getNum() {
return of(this.nums);
}
public addNum(num) {
this.nums.push(num);
}
Why when i click on addNum, in component1 doesn't work subscribe and value doesn't change. How to do it properly on this example?
CodePudding user response:
You need to push the change to nums to the obersvable using .next()
https://rxjs.dev/guide/observable
CodePudding user response:
The issue is that when you call this.numService.getNum()
in ngOnInit
the subscribe method is only called once ngOnInit is executed. That happens because NumService.getNum()
returns an observable created with the of()
operator. Such an observable emits only once and then completes. So you get only initial value of NumService.nums
.
Solution would be to turn numService.nums
into a BehaviorSubject and subscribe to it.
class NumService {
private numsSubject$: BehaviorSubject<number[]> = new Subject<number[]>([]);
nums$: Observable<number[]> = this.numsSubject$.asObservable();
addNum(num: number): void {
const nums = this.numsSubject$.getValue();
this.numsSubject$.next([...nums, num]);
}
}
class Component1 {
nums: Array<number> = [0, 1, 2, 3];
ngOnInit(): void {
this.numService.nums$.subscribe((res) => {
this.num = res;
});
}
addNum(): void {
this.numService.addNum(6);
}
}
CodePudding user response:
you are facing two problems:
- Every time you call the service function
numService.getNum()
you are creating a new observable. - The function
of
creates a special observable which only emits its value once.
Instead you should have your service maintain a single observable, preferably a ReplaySubject (so it retains the previous value for subscriptions)
something like this should work, in your service:
nums$ = new ReplaySubject<int[]>([]);
nums = []
public addNum(num) {
this.nums.push(num);
this.nums$.next(this.nums)
}
then from your component, you should not subscribe (to avoid the usual observable memory leak), but expose the service's observable:
numsAtComponent$ = this.numService.nums$
And finally from your template, you subscribe to the component variable and show its value like this:
<div>
{{ numsAtComponent$ | async }}
</div>