Smart Counter
Last updated
Was this helpful?
Last updated
Was this helpful?
Was this helpful?
import { timer, fromEvent, merge } from 'rxjs';
import {
switchMap,
startWith,
scan,
takeWhile,
takeUntil,
filter,
mapTo,
map,
tap,
pluck
} from 'rxjs/operators';
let currentNumber = 0;
// elems
const input: any = document.getElementById('range');
// utility functions
const takeUntilFunc = (endRange, currentNumber) => {
return endRange > currentNumber
? val => val <= endRange
: val => val >= endRange;
};
const positiveOrNegative = (endRange, currentNumber) => {
return endRange > currentNumber ? 1 : -1;
};
const updateHTML = id => val => (document.getElementById(id).innerHTML = val);
// streams
const enter$ = fromEvent(input, 'keyup').pipe(
pluck('code'),
filter(code => code === 'Enter')
);
enter$
.pipe(
map(() => parseInt(input.value)),
switchMap(endRange => {
return timer(0, 20).pipe(
mapTo(positiveOrNegative(endRange, currentNumber)),
startWith(currentNumber),
scan((acc, curr) => acc + curr),
takeWhile(takeUntilFunc(endRange, currentNumber))
);
}),
tap(v => (currentNumber = v)),
startWith(currentNumber)
)
.subscribe(updateHTML('display'));<div class="container">
<input id="range" type="number" />
<h1 id="display"></h1>
</div>import { Component, Input, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { timer } from 'rxjs/observable/timer';
import { switchMap, startWith, scan, takeWhile, takeUntil, mapTo } from 'rxjs/operators';
@Component({
selector: 'number-tracker',
template: `
<h3> {{ currentNumber }}</h3>
`
})
export class NumberTrackerComponent implements OnDestroy {
@Input()
set end(endRange: number) {
this._counterSub$.next(endRange);
}
@Input() countInterval = 20;
public currentNumber = 0;
private _counterSub$ = new Subject();
private _onDestroy$ = new Subject();
constructor() {
this._counterSub$
.pipe(
switchMap(endRange => {
return timer(0, this.countInterval).pipe(
mapTo(this.positiveOrNegative(endRange, this.currentNumber)),
startWith(this.currentNumber),
scan((acc: number, curr: number) => acc + curr),
takeWhile(this.isApproachingRange(endRange, this.currentNumber))
)
}),
takeUntil(this._onDestroy$)
)
.subscribe((val: number) => this.currentNumber = val);
}
private positiveOrNegative(endRange, currentNumber) {
return endRange > currentNumber ? 1 : -1;
}
private isApproachingRange(endRange, currentNumber) {
return endRange > currentNumber
? val => val <= endRange
: val => val >= endRange;
}
ngOnDestroy() {
this._onDestroy$.next();
this._onDestroy$.complete();
}
}<p>
<input
type="number"
(keyup.enter)="counterNumber = vanillaInput.value"
#vanillaInput
/>
<button (click)="counterNumber = vanillaInput.value">
Update number
</button>
</p>
<number-tracker [end]="counterNumber"></number-tracker>