Regular Expressions—a Rite of Passage: Completing the Application

rhieger

Robert Hieger

Posted on February 28, 2023

Regular Expressions—a Rite of Passage: Completing the Application

JavaScript in Plain English logo

This article was first published on JavaScript in Plain English.

Part 3: Building from Infrastructure to Completed Application

Woman with Computer Code Superimposed

Photo by ThisisEngineering RAEng on Unsplash

Table of Contents

WELCOME BACK!

Completing the Application

     Step 7. Coding the Callback Functions

        The populateResultBox() Function
        The depopulateResultBox() Function

     Step 8. Coding the Event Listeners

        Add an Event Listener to the Validate Zip Codes Button
        Add an Event Listener to the Reset Button

Conclusion

Next Steps

References


WELCOME BACK!

Our moment has arrived. We are now ready to finish our application started in Regular Expressions—a Rite of Passage: From Theory to Practice.

Completing the Application

We left off at Step 6 in Part 2 of this tutorial, in which we built out the infrastructure of our application, providing all necessary data structures and helper functions.

Two steps remain to complete the application:

     1. We need to code the callback functions that will be used by the two
         event listeners mentioned in Part 2.

     2. We need to write the event listeners that will call the callback functions
         in order to carry out their work.


Step 7. Coding the Callback Functions

Let’s think for a moment about what these callback functions need to accomplish. We know that they are attached as arguments to two event listeners, one listening for a click event on the Validate Zip Codes button and the other listening for a click event on the Reset button.

We will be picking up exactly where you left off in your code at the end of
Part 2.

For the Validate Zip Codes button, we need a callback function that will swap contents with the default message of NO MATCH and populate its parent instead with a scrolling window of valid zip code matches.


The populateResultBox() Function

Search in the starter code for the line that reads:

// TO BE DONE: Code populateResultBox() callback function.

and replace it with the following lines of code:

const populateResultBox = () => {

  resultBox.classList.remove(default-result);
  resultBox.removeChild(placeHolder);
  resultBox.classList.add(custom-scrollbar);

  createParagraphText();

  // Create paragraphs and set textContent only
  // if not already created. Prevents doubling
  // of result data if old paragraphs have not
  // yet been garbage collected.

  if (paragraphs.length === 0) {
    createParagraphs();
  }
  // Append all result paragraphs to resultBox.

  appendParagraphs(resultBox, paragraphs);

};

Enter fullscreen mode Exit fullscreen mode
Code Listing 1. The populateResultBox() Callback Function

A lot is happening in this function, though much of it has been broken down in our discussion of the helper functions. Nonetheless, there are still a few remaining new concepts here.

The first three lines of code are manipulation of the DOM as we have not seen before in this tutorial. To fully understand these three lines, we will need to look at some code snippets from our HTML and CSS.

Code Listing 2 below shows the HTML element to which resultBox refers:

<div id="results"
class="results-data-dimensions default-result">
  <p class="default-message" id="message">no match</p>
  <!-- Dynamic content lives here. -->
</div>

Code Listing 2. HTML Elements Captured by resultBox

You might recall from Part 2 a code listing that started with the element
<div id= “getResults”>, which contains the entire widget with the two buttons and the <p> element with the NO MATCH message shown in
Code Listing 2 above.

We need to take a brief dip into the CSS code to understand fully what is being changed by populateResultBox().

Take a look at Code Listing 3 below:

.default-result {
  background-color: #808080;
}
Enter fullscreen mode Exit fullscreen mode
Code Listing 3. CSS Class Controlling resultBox Background Color

As you can see, the .default-result class specifies a gray background. As this background is part of a placeholder for the results about to populate resultBox, we want to clear it.

Now let’s look at the first line of code in the populateResultBox() callback function:

resultBox.classList.remove(default-result);
Enter fullscreen mode Exit fullscreen mode

As we know, the resultBox object captures <div id=“results”> shown in Code Listing 2.

In the Document Object Model (DOM), HTML elements have the classList property, which keeps track of all CSS classes associated with them.

The remove() method chained to the classList property does exactly what it says—it removes the class passed to it from the classList. This does not mean the class is deleted from the linked CSS file. What it does mean is that the web page displayed in your browser will no longer show a gray background in the scrolling window of results.

Now let’s review our second line of code:

resultBox.removeChild(placeHolder);
Enter fullscreen mode Exit fullscreen mode

This line of code is concerned with nodes in the DOM tree. As you
might recall from earlier, placeHolder is the DOM node that captures
<p class=“default-message” id=“message”>no match</p>.

This paragraph is the NO MATCH message shown on the opening screen of our application. Obviously, we need to remove this from our display.

The removeChild() method removes a child node from a parent node. placeHolder is a child node of resultBox. As in the case of the remove() method above, removeChild() leaves the paragraph in the HTML untouched. It is merely removed from our live display.

Next let’s review our third line of code:

resultBox.classList.add(custom-scrollbar);
Enter fullscreen mode Exit fullscreen mode

Here, we are doing something quite different. Here, we add a CSS class
to reasultBox. Code Listing 4 below shows the code for CSS class .custom-scrollbar:

.custom-scrollbar {
  --scrollbar-foreground: #a239ca;
  --scrollbar-background: rgba(162, 57, 202, 0.25);
  /* Foreground and Background Colors */
  scrollbar-color: var(--scrollbar-foreground)
  var(--scrollbar-background);
}
Enter fullscreen mode Exit fullscreen mode
Code Listing 4. CSS Class Controlling Scrollbar Styling for resultBox

Without diving deeply into the above code, all we need to know is that this class sets foreground and background styling for the scrollbar in resultBox once it has been populated. For those who are interested in delving deeper into the styling, the above style was informed by the work of CSS Tricks (Coyier, “Using Custom Properties for Styling Scrollbars in CSS”).

The add() method chained to the classList property, in contrast to the remove() method we saw moments ago, adds a CSS class to resultBox.

The remaining code in the populateResultBox() callback function has already been covered in Part 2, Step 6 of this tutorial.


The depopulateResultBox() Function

Now we can turn our attention to coding the depopulateResultBox() callback function. As you might guess, the purpose of this function is to remove the paragraphs that populated resultBox and restore the default message and styling associated therewith.

Search in the starter code for the line that reads:

// TO BE DONE: Code depopulateResultBox() callback function.

and replace it with the following lines of code:

const depopulateResultBox = () => {
  while (resultBox.firstChild) {
   resultBox.removeChild(resultBox.firstChild); 
  }
  resultBox.classList.remove(custom-scrollbar);
  resultBox.classList.add(default-result);
  resultBox.appendChild(placeholder);
};
Enter fullscreen mode Exit fullscreen mode
Code Listing 5. The depopulateResultBox() Function

We've met every method seen in this function when we coded the depopulateResultBox() helper function above. So here is a quick breakdown of what is happening in this code:

     1. We start with a while loop that takes a single argument—
         resultBox.firstChild. We already know that resultBox is a
         DOM node. As such it exposes properties and methods. The          firstChild property captures the first child of resultBox,
         which would be the first paragraph in resultBox.

     2. The argument in this while loop is a Boolean that evaluates to
          true if there is a firstChild paragraph node in resultBox. Each
          time through the loop,

         resultBox.removeChild(resultBox.firstChild);

         is executed, it removes one paragraph. On each iteration of the
         loop the next paragraph in line becomes the firstChild. Once
         there is no firstChild left, the loop terminates because no
         paragraphs remain.

     3. Once all paragraphs have been removed the three remaining
          lines of code outside of the while loop remove the
         .custom-scrollbar class, thus restoring the gray background,
         and finally uses the appendChild() method to restore the
         NO MATCH message.

We have now completed our callback functions and are ready to proceed
to the last step—coding the event listeners for the Validate Zip Codes
and Reset buttons.


Step 8. Coding the Event Listeners

Now we approach the ultimate step in completing our application—that of coding the event listeners
for our buttons.

To start, I would like to recall two declared node objects that we created at the beginning of Part 2, Regular Expressions—a Rite of Passage: From Theory to Practice:

const resultButton = document.getElementById(validate);
const resetButton = document.getElementById(reset);
Enter fullscreen mode Exit fullscreen mode
Code Listing 6. Nodes in Need of Event Listeners

These two lines of code are our starting point as we will need them to build our event listeners.

resultButton is the DOM node that captures the
<button class=“controlButton” id=“validate”> element in our index.html file.

resetButton is the DOM node that captures the
<button class=“controlButton” id=“reset”> element.

With this new information we can begin.


Add an Event Listener to the Validate Zip Codes Button

Search in the starter code for the line that reads:

// TO BE DONE: Code resultButton event listener.

and replace it with the following line of code:

resultButton.addEventListener(click, populateResultBox);
Enter fullscreen mode Exit fullscreen mode

Using the resultButton DOM node, we chain the addEventListener() method to it. This method takes two arguments, as you see.

The first specifies what type of event to be listened for (there are a number of different kinds). Ours is a click event, which means that JavaScript will listen for any mouse clicks on resultButton.

The second is the callback function to be executed when the click event is detected. The callback function can be an anonymous function included as the second argument. In our case, the callback function is populateResultBox().

With this event listener in place, we should now be able to populate the resultBox with valid zip code matches when we click the Validate Zip Codes button. Let’s test this.

If you have not already done so, open the index.html file in your favorite browser. If you have the file open already, make sure to refresh your browser.

Click on the Validate Zip Codes button.

Your screen should look much like that shown below in Figure 1:

Fig. 1. resultBox with Scrollbar and Populated with Valid Zip Codes

Fig. 1. resultBox with Scrollbar and Populated with Valid Zip Codes

Add an Event Listener to the Reset Button

Now let’s code the event listener for the Reset button.

Search in the starter code for the line that reads:

// TO BE DONE: CODE resetButton event listener.

and replace it with the following line of code:

resetButton.addEventListener(click, depopulateResultBox);
Enter fullscreen mode Exit fullscreen mode

This event listener also listens for a click event, this time on our Reset button, and calls the depopulateResultBox() callback function to reset our page to its beginning state.

To test this out, refresh your browser. Now click the Validate Zip Codes button. Once you see that the resultBox has been populated with the zip code matches, click on the Reset button.

If all goes according to plan, your screen should reset to its initial state with the message NO MATCH displayed where the scrolling list of zip code matches were.


Conclusion

CONGRATULATIONS! You have completed the demo zip code validation Single Page Application (SPA).

If your code is not working and you are not sure why, you can download my completed code and compare yours with it to find any errors.

You can also view the live application here on codepen.io.


Next Steps

Now that you have a functional demo web app that returns valid zip codes from a test string, where might you go from here?

Play around with the finished code you have. Here are a couple suggestions:

  1. Experiment with further de-coupling of helper functions from the data upon which they operate, as in my example of the createParagraphs() function.

  2. Think about how you might make this a truly interactive application in which a user would simply input a test string and click on the Validate Zip Codes button to get the result(s).

Finally, feel free to fork [my repository(https://github.com/RHieger/regex-zip-code-tutorial) and create your own version.

Happy coding!


                                                  References

Coyier, Chris. “The Current State of Styling Scrollbars in CSS (2022
     Update): CSS-Tricks.”
CSS Tricks, 21 Feb. 2022,
     https://css-tricks.com/the-current-state-of-styling-scrollbars-in-css/#aa-using-custom-properties-for-styling-scrollbars-in-css.

💖 💪 🙅 🚩
rhieger
Robert Hieger

Posted on February 28, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related