Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
September 13, 2021 03:35 pm GMT

Creating a countdown timer RxJS vs Vanilla JS

Let's see our requirements.

  1. Create a Countdown timer
  2. start button which will start the timer from the current stage
  3. pause button which will pause the timer, so that, we can resume the timer on clicking start again
  4. stop button which will stop the timer, and reset the timer number.

Timer

Let's see how we can do with Vanilla JS.

<h3 id="result"></h3><button id="startBtn">Start</button><button id="pauseBtn">Pause</button><button id="stopBtn">Stop</button>

Let's first select the elements and add click listeners

const startBtn = document.querySelector('#startBtn');const stopBtn = document.querySelector('#stopBtn');const pauseBtn = document.querySelector('#pauseBtn');const result = document.querySelector('#result');startBtn.addEventListener('click', () => {  //start the interval});stopBtn.addEventListener('click', () => {  //stop the interval and reset value in HTML});pauseBtn.addEventListener('click', () => {  // pause the interval});

We will have to create few variables.

  1. to store the current value
  2. to store the initial value
  3. to store the interval ( Since we want to do an action continuously on a specific interval, we will use setInterval )
let interval;const initialValue = 10;let currentValue = initialValue;

We will also set the current value to the HTML

result.innerHTML = `${currentValue}`;

Now, we will create the function to start the timer and call this function on click of start button

const startInterval = () => {  clearInterval(interval);  interval = setInterval(() => {    currentValue -= 1;    if (currentValue <= 0) {      currentValue = initialValue;      clearInterval(interval);    }    result.innerHTML = `${currentValue}`;  }, 1000);};startBtn.addEventListener('click', () => {  startInterval();});

On click of stop button, we will clear the interval, and also reset the value.

stopBtn.addEventListener('click', () => {  currentValue = initialValue;  clearInterval(interval);  result.innerHTML = `${currentValue}`;});

On click of Pause button, we are just clearing the interval, and not resetting the value.

pauseBtn.addEventListener('click', () => {  clearInterval(interval);});

Here is the whole code.

Now, lets try the same with RxJS

First, same selectors again

const startBtn = document.querySelector('#startBtn');const stopBtn = document.querySelector('#stopBtn');const pauseBtn = document.querySelector('#pauseBtn');const counterDisplayHeader = document.querySelector('h3');

Now, lets create event streams for the button clicks

const startClick$ = fromEvent(startBtn, 'click');const stopClick$ = fromEvent(stopBtn, 'click');const pauseBtn$ = fromEvent(pauseBtn, 'click');

Let's define a starting value, so that, countdown can start from any number defined.

const startValue = 10;

Now, the RxJS magic

merge(startClick$.pipe(mapTo(true)), pauseBtn$.pipe(mapTo(false)))  .pipe(    switchMap(shouldStart => (shouldStart ? interval(1000) : EMPTY)),    mapTo(-1),    scan((acc: number, curr: number) => acc + curr, startValue),    takeWhile(val => val >= 0),    startWith(startValue),    takeUntil(stopClick$),    repeat()  )  .subscribe(val => {    counterDisplayHeader.innerHTML = val.toString();  });

Let's try to breakdown

First, we will just try only the start. On click of start, we want to start an interval.

startClick$  .pipe(    switchMapTo(interval(1000)),

and, we want to decrement the value by 1 and start the value from the starting value. so, we will use two operators here

startClick$  .pipe(    switchMapTo(interval(1000)),    mapTo(-1),    scan((acc: number, curr: number) => acc + curr, startValue)

Now, we need to have option to stop the timer. We want to stop the timer on two scenarios.

  1. When the value reaches 0
  2. When user press stop button
startClick$  .pipe(    switchMapTo(interval(1000)),    mapTo(-1),    scan((acc: number, curr: number) => acc + curr, startValue),    takeWhile(val => val >= 0),    takeUntil(stopClick$)

We want to start with a value of startValue

startClick$  .pipe(    switchMapTo(interval(1000)),    mapTo(-1),    scan((acc: number, curr: number) => acc + curr, startValue),    takeWhile(val => val >= 0),    startWith(startValue),    takeUntil(stopClick$)  )

Now, in case of pause button click, we just want to emit an empty observable.

pauseBtn$    .pipe(      switchMapTo(EMPTY))    )

Finally, we want to combine both start and pause button clicks. We are not really interested in event details. instead, we just want to decide between interval or EMPTY observable based on click. So, we will just map the button clicks to true or false. if start button is clicked, map the value to true and if pause button is clicked, we map the value to false, so that, we can check on switchMap.

merge(startClick$.pipe(mapTo(true)), pauseBtn$.pipe(mapTo(false)))  .pipe(    switchMap(shouldStart => (shouldStart ? interval(1000) : EMPTY))

And, we want to start again once the timer is stopped. For that, we are using repeat() operator

And, you can see and play around with the whole code here,

So, with RxJS, I didn't have to create any extra external variables, intervals etc. Also, no need to add separate logic for start, stop, pause. Whole logic is added in a single chain of commands.

Isn't it neat? What do you think of this? Is there any better way to do this?

Let me know in comments.

   const You = 'Reader';   if(You === 'Fresher' || You === 'Took a Break from Job'){      if(You Are 'Looking For A Job' && You Love JavaScript){

Click Here to know more about our Training Program

      }   }

Original Link: https://dev.to/jintoppy/creating-a-countdown-timer-rxjs-vs-vanilla-js-5g05

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To