At https://www.learnrxjs.io/recipes/smartcounter.html I found a great example of an numbercounter in Angular 2+, the code looks likes:
@Component({
selector: 'number-tracker',
template: `
<h3> {{ currentNumber }}</h3>
`
})
export class NumberTrackerComponent implements OnDestroy {
@Input()
set end(endRange: number) {
this._counterSub$.next(endRange);
}
public currentNumber = 0;
private _counterSub$ = new Subject();
private _subscription : Subscription;
constructor() {
this._subscription = this._counterSub$
.switchMap(endRange => {
return timer(0, 20)
.mapTo(this.positiveOrNegative(endRange, this.currentNumber))
.startWith(this.currentNumber)
.scan((acc, curr) => acc + curr)
// .delayWhen(i => {
// easing here
// })
.takeWhile(this.takeUntilFunc(endRange, this.currentNumber));
})
.subscribe(val => this.currentNumber = val);
}
private positiveOrNegative(endRange, currentNumber) {
return endRange > currentNumber ? 1 : -1;
}
private takeUntilFunc(endRange, currentNumber) {
return endRange > currentNumber
? val => val <= endRange
: val => val >= endRange;
}
ngOnDestroy() {
this._subscription.unsubscribe();
}
}
Now this works good, but I want to pass a variable currentNumber instead of the this.currentNumber default 0.
Until now I've come so far:
public currentNumber: number;
...
@Input()
set fanCountPrev(startRange: number) {
this.currentNumber = startRange
console.log('startRange: ', this.currentNumber)
}
...
But when a new value arrives, there this.currentNumber is not set to the previous version.
Do you have any tips or example to accomplish this?
The problem here is that the subscription is made on the constructor, while the Input() binding are resolved on the ngOnInit lifehook. Also, in this case there is not a good practise to modify manually on runtime the this.currentNumber variable, so is an internal state of the observable calculation. The only think I seee posible is to modify it onInit, for this, and as I said, you must create the subscription in the ngOnInit lifehook function like so:
@Component({
selector: 'number-tracker',
template: `
<h3> {{ currentNumber }}</h3>
`
})
export class NumberTrackerComponent implements OnDestroy {
@Input()
set end(endRange: number) {
this._counterSub$.next(endRange);
}
@Input()
set fanCountPrev(startRange: number) {
this.currentNumber = startRange
console.log('startRange: ', this.currentNumber)
}
private currentNumber = 0;
private _counterSub$ = new Subject();
private _subscription : Subscription;
constructor() {
}
ngOnInit() {
this._subscription = this._counterSub$
.switchMap(endRange => {
return timer(0, 20)
.mapTo(this.positiveOrNegative(endRange, this.currentNumber))
.startWith(this.currentNumber)
.scan((acc, curr) => acc + curr)
// .delayWhen(i => {
// easing here
// })
.takeWhile(this.takeUntilFunc(endRange, this.currentNumber));
})
.subscribe(val => this.currentNumber = val);
}
private positiveOrNegative(endRange, currentNumber) {
return endRange > currentNumber ? 1 : -1;
}
private takeUntilFunc(endRange, currentNumber) {
return endRange > currentNumber
? val => val <= endRange
: val => val >= endRange;
}
ngOnDestroy() {
this._subscription.unsubscribe();
}
}
But remember, this solution will work only for the initilitzation. If you change the variable during the existence of this component, this wouldn't work. But as I said, it is not a good practise in this case because is an intern calculated state of the component, it only make sense on the initialitzation.
Hope this helps.