Lesson Tuesday

Over the last two lessons, we used test-driven development to build some basic functionality for a word counter program. This program can count the number of words in a passage of text and also count the number of occurrences of that word.

In this lesson, we'll add a user interface for our application, paying close attention to separation of logic as we go.

Spoiler alert: because of the way we're designing our application, it's going to be much easier to keep our logic separate. That's because we've written and tested our business logic completely separately from our user interface.

Let's start by adding our UI files. Here are all the files that text-analyzer should include:

index.html
js/scripts.js
css/styles.css
README.md

Note the file paths above (the js directory should contain scripts.js and the css directory should contain styles.css). We will use a CDN link so we don't need to include a Bootstrap file. You are always welcome to include Bootstrap directly in the project if you wish.

Here's our scripts.js file so far:

scripts.js
// Business Logic

function wordCounter(text) {
  if (text.trim().length === 0) {
    return 0;
  }
  let wordCount = 0;
  const wordArray = text.split(" ");
  wordArray.forEach(function(element) {
    if (!Number(element)) {
      wordCount++;
    }
  });
  return wordCount;
}

function numberOfOccurrencesInText(word, text) {
  if (text.trim().length === 0) {
    return 0;
  }
  const wordArray = text.split(" ");
  let wordCount = 0;
  wordArray.forEach(function(element) {
    if (element.toLowerCase().includes(word.toLowerCase())) {
      wordCount++;
    }
  });
  return wordCount;
}

// UI Logic

We have two functions that we can plug into our user interface where needed.

Note that we've also added a comment at the end of the file for UI Logic. We will put all of our UI logic below this line. Again, you won't see this comment in real-world code bases but it will help us keep things separate for now. As we've mentioned previously, we'll learn how to separate our business and user interface logic into different files in Intermediate JavaScript.

Next, let's add a basic index.html file.

index.html
<!DOCTYPE html>
<html lang="en-US">
<head>
  <title>Text Analyzer</title>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
  <link href="css/styles.css" rel="stylesheet" type="text/css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="js/scripts.js"></script>
</head>
<body>
  <div class="container">
      <h2>Text Analyzer</h2>
    <form id="word-counter">
      <div class="form-group">
        <p>Input a text passage to get a total word count:</p>
        <textarea id="text-passage" name="text-passage" class="form-control"></textarea>
        <p>Optionally enter a word to count the number of times it occurs in the passage:</p>
        <input type="text" id="word" name="word" class="form-control">
        <br>
        <button type="submit" class="btn btn-success">Submit Survey</button>
      </div>
    </form>
    <p>Total Word Count: <span id="total-count"></span></p>
    <br>
    <p>Selected Word Count: <span id="selected-count"></span></p>
    <span id="bolded-passage"></span>
  </div>
</body>
</html>

This includes a form with a textarea (a larger text field) for the text passage as well as a simple text field for inputting a word.

Note also that we've included a span with id="bolded-passage". We will be adding some functionality to further demonstrate how to separate logic later in this lesson.

Now let's get to work on our UI logic. Add this code below the UI Logic comment in scripts.js:

js/scripts.js
// UI Logic

$(document).ready(function(){
  $("form#word-counter").submit(function(event){
    event.preventDefault();
    const passage = $("#text-passage").val();
    const word = $("#word").val();
    const wordCount = wordCounter(passage);
    const occurrencesOfWord = numberOfOccurrencesInText(word, passage);
    $("#total-count").html(wordCount);
    $("#selected-count").html(occurrencesOfWord);
  });
});

This should all be review. When a form is submitted, we'll grab field values for passage (the entire text) and word. Then we'll call our wordCounter() and numberOfOccurrencesInText() functions and use jQuery's html method to return the values of those functions.

Our code is very nicely separated. Let's try it out in the console. Be forewarned, though. There is a bug! See if you can figure out what it is before moving on.

In the next lesson, we'll discuss this bug, walk through the debugging process, and then fix it. But we recommend seeing if you can find the bug, figure out what the problem is, and fix it on your own before moving to the next lesson. Don't be hard on yourself if you can't find it. Just look at it as an opportunity to practice debugging.

Lesson 20 of 38
Last updated more than 3 months ago.