Search⌘ K
AI Features

Assembling the Stopwatch

Explore how to assemble a stopwatch application by integrating multiple RxJS observables and handling events with subscriptions. Understand using TypeScript to specify HTML elements, applying operators like takeUntil to manage event lifecycles, and separating business logic from UI. This lesson guides you through creating a responsive stopwatch that efficiently manages event streams and updates the view.

Stopwatch application

All three observables have been created. Now it’s time to assemble everything into an actual program.

Bud1
x.html
index.htmlIlocblob;(ÿÿÿÿÿÿpackage-lock.jsonIlocblob©(ÿÿÿÿÿÿpackage.jsonIlocblob(ÿÿÿÿÿÿpackage.json.sb-a48e3b48-LE4G1wIlocblob˜ÿÿÿÿÿÿstopwatch-complete.tsIlocblob…(ÿÿÿÿÿÿstopwatch.tsIlocblobó(ÿÿÿÿÿÿ
tsconfig.jsonIlocblob;˜ÿÿÿÿÿÿwebpack.config.jsIlocblob©˜ÿÿÿÿÿÿ @€ @€ @€ @E
DSDB `€ @€ @€ @
Stopwatch application project

🙋‍♂️ Joe asks: What does that <HTMLElement> mean?

This course uses TypeScript for all the examples. The <angle bracket notation> denotes the specific return type for querySelector. TypeScript knows that querySelector will return some kind of element. In this case, we know specifically that we’re querying for an element of the HTML variety, so we use this syntax to override the generic element. With that override, TypeScript now knows that resultsArea has properties specific to an HTMLElement, such as .innerText. We don’t need to use the angle brackets when we query for button elements, because we’re not doing anything button specific with those variables, so the generic Element type suffices.

Stopwatch code explanation

There are a few new concepts in the stopwatch example in stopwatch.ts, so let’s take it blow-by-blow.

To start, there are:

  • six variables, among which
  • three elements from the page
  • and three observables

You can tell which ones are observables because we annotated the variable name with a dollar sign.

subscribe function

TypeScript 3.3.4
startClick$.subscribe(() => {
tenthSecond$
.pipe(
map(item => (item / 10)),
takeUntil(stopClick$)
)
.subscribe(num => resultsArea.innerText = num + 's');
});

The first line of business logic is a subscription to startClick$, which creates a click event handler on that element. At this point, no one’s clicked the Start button, so Rx hasn’t created the interval or an event listener for the stop button (saving CPU cycles without extra work on your part).

subscribe() triggering

When the Start button is clicked, the subscribe function is triggered (there’s a new event). The actual click event is ignored, as this implementation doesn’t care about the specifics of the click just that it happened. Immediately, tenthSecond$ runs its constructor (creating an interval behind the scenes), because there’s a subscribe call at the end of the inner chain in Line 7. Every event fired by $tenthSecond runs through the map function, dividing each number by 10. Suddenly, an unexpected operator appears in the form of takeUntil.

takeUntil and unsubscribe()

takeUntil is an operator that attaches itself to an observable stream and takes values from that stream until the observable that’s passed in as an argument emits a value. At that point, takeUntil unsubscribes from both.

In this case, we want to continue listening to new events from the timer observable until the user clicks the Stop button. When the Stop button is pressed, Rx cleans up both the interval and the Stop button click handler. This means that both the subscribe and unsubscribe calls for stopClick$ happen at the library level. This helps keep the implementation simple, but it’s important to remember that the (un)subscribing is still happening.

Separating business logic from views

Finally, we put the latest value from tenthSecond$ on the page in the subscribe call. Putting the business logic in Rx and updating the view in the subscribe call is a common pattern you’ll see in both this course and in any observable-heavy frontend application.

You’ll notice that repeated clicks on the Start button cause multiple streams to start. The inner stream should listen for clicks on either button and pass that to takeUntil. This involves combining two streams into one, a technique you’ll learn in the next chapter.

Achievement Unlocked! 🎉

Congratulations! You have learned the Rx basics and made a full-fledged stopwatch application.

Brilliant work! Give yourself a round of applause!