Exercise 1

Introduction to JavaScript - Exercise 1

Exercise 1 - review of Introduction to JavaScript

Whenever I try to learn something new, I find it useful to write code that is similar to what I have learned. I attempt to write some code that uses the same concepts as what I have just learned. At the same time, I try to make the code different enough so that it is not just the previous code with cosmetic changes. To do this, I start by identifying the key concepts that the previous code uses. Here is what I would I see as the key concepts of this lesson.

Key concepts from Introduction to Javascript

  • The JavaScript code should go inside a <script> element inside the <head> section of the HTML document.

  • To manipulate a HTML element, you need to be able to select that HTML element. A good way to do this is to give that element and id attribute.

  • To make a button or a table cell respond to a mouse click, the code must attach an EventListener by using the addEventListener(event, handler) function. This is where event is the type of event to listen for, and handler is the function that called to handle that event. For a mouse click, the event being handled is "click".

  • Hitting F12 to open the DevTools console is an essential way to debug your code. In addition, using the console.log() function to print to that console, is a powerful and important way to develop your code.

Hitting F12 and right-clicking and then choosing Inspect, both open the DevTools. But, while F12 opens up the entire DevTools interface, right-clicking on an element and choosing Inspect will focus on the Elements panel and highlight the element that you right-clicked on.

Exercise 1 - Responding to a button click

For this exercise, you want to make a simple web application that lets the user enter a number into an input text box. The user will click on a button labeled Draw and the application will draw white squares. The number of white squares will be set by the number the user entered into the input text box.

Hint: using the character '\u25a1' will use Unicode to draw a white square. Using a HTML <label> element to hold several of these characters will make it appear as though you have drawn that number of white squares.

Creating a prototype solution

Even for a very small project, I find it useful to create a prototype solution. A prototype does not solve the whole problem, but represents just enough of a start to make developing the project easier. Here is a template file, that could be used to start a very simple web application that uses JavaScript:

template1.html
<!DOCTYPE html>
<html>
   <head>
      <script>
        addEventListener('DOMContentLoaded', init);

        function init() {
          // code here
        }
      </script>
   </head>
   <body>
   </body>
</html>

Line 1 has the DOCTYPE declaration that makes this a HTML5 document. Lines 3-11, define the <head> section. To keep the code separate from the markup, we will generally place our <script> elements inside the <head> section. Line 5 just ensures that the init() function is called after the DOM contents have completely loaded. That means that the HTML markup will be rendered before the init() function is called. This is not the only way to organize such a page, but it is a good consistent way to create this type of document.

Lines 7-9 form the skeleton of the init() function. This function will be called every time the application is loaded, and will initialize anything that is needed to be set up before the user starts to interact with the application.

Modifying the file

I start with a copy of this template file, and named that file "exercise1.html". This is how I created a prototype for this simple project.

exercise1.html
<!DOCTYPE html>
<html>
   <head>
      <script>
        addEventListener('DOMContentLoaded', init);
        const mysquare = '\u25a1';

        function init() {
          const mylabel = document.getElementById('mylabel');
          let mytext = mysquare + mysquare;
          let contents = document.createTextNode(mytext);
          mylabel.appendChild(contents);
        }
      </script>
   </head>
   <body>
     <label id="mylabel"></label>
   </body>
</html>

On line 6, I created a constant that will be the character for a white square. I place this at the top of the script, so that it will be available throughout the <script> element. I declare this a constant using (const) as the value of this does not change.

On line 17, a <label> element with an id="label" attribute is used. Remember, that giving an element an id attribute is one good way of making it so that we can reference that element using JavaScript.

With the init() function, line 9 obtains a reference to the <label> element and calls this reference mylabel. Line 10 just creates some text by concatenating mysquare with itself. Line 11 creates a TextNode from that text, and line 12 appends it to the element referenced by mylabel.

I started up http-server in the directory where I stored exercise1.html. So, when viewed in the browser, this is what you would see:

exercise1 1

I then, right-clicked on one of the white squares and chose Inspect:

exercise1 2

This will bring up DevTools with the element I right-clicked on highlighted as shown in the next screen shot:

exercise1 3

The prototype serves its purpose. We can see what two white squares looks like, and we know that we can place the squares inside the <label> element. Now that we know that this works, we can add an input field and a button to get the rest of the simple project working. We can do this in a couple of steps.

Here is the next iteration of the code:

exercise1.html
<!DOCTYPE html>
<html>
   <head>
      <script>
        addEventListener('DOMContentLoaded', init);
        const mysquare = '\u25a1';

        function handle_draw_button() {
          console.log('handle_draw_button() called');
        }

        function init() {
          const draw_button = document.getElementById('draw_button');
          draw_button.addEventListener('click', handle_draw_button);
          /*
          const mylabel = document.getElementById('mylabel');
          let mytext = mysquare + mysquare;
          let contents = document.createTextNode(mytext);
          mylabel.appendChild(contents);
          */
        }
      </script>
   </head>
   <body>
     Enter number of squares:
     <input type="text" id="num_squares_text">
     <button id="draw_button">Draw</button><br>
     <label id="mylabel"></label>
   </body>
</html>

The new lines are lines 8-10, 13-14, 15-20 and 25-27.

Let’s start with the changes to the markup inside the <body> element. These are the changes on lines 25-27. Line 25 is just some text that serves as a prompt. Line 26 creates an <input> element with an id="num_squares_text" attribute. We will eventually need to get a reference to this <input> element so that we can get the user’s input for the number of squares to draw. Line 27 creates a <button> element with an id="draw_button" attribute. This button will have the text "Draw" on the surface of the button. With just those changes, you could refresh the page to see that the markup looks correct.

Here is a screen shot that shows what that would look like if you refresh the browser and right-click on the text box to select Inspect:

exercise1 4

Now, let’s look at the changes inside the <script> element. First off, lines 15-20 just comment out the lines that used to draw two white squares inside the label element. I did not erase those lines yet, as they have some basic code that we will use in the handle_draw_button() function. Line 13 gets a reference to the button labeled "Draw". Line 14 makes it so that clicking on that button will cause the handle_draw_button() function will be called.

Lines 8-10 define the handle_draw_button() function. Right now, all this function will do is print "handle_draw_button() called" to the console.

Here is a screen shot showing the console in DevTools after the user has clicked on the "Draw" button:

exercise1 5

Completing the code

Now that the pieces are mainly in place, all we need to do is to complete the handle_draw_button() function to update the <label> element. Here is a list of the steps that we need to carry in that function:

  • Obtain a reference to the <input> element with the id="num_squares_text" attribute. Use that reference to obtain the text inside that input text box.

  • Convert the value from the text box into a number. Use that number to control a for loop that generates text that contains that number of white squares.

  • Create a TextNode from the generated text.

  • Get a reference to the <label> element with the id="mylabel" attribute. Use that reference to replace that label’s contents with the TextNode from the generated text.

Here is a possible solution to these steps:

exercise1.html
<!DOCTYPE html>
<html>
   <head>
      <script>
        addEventListener('DOMContentLoaded', init);
        const mysquare = '\u25a1';

        function handle_draw_button() {
          //console.log('handle_draw_button() called');
          const num_squares_text = document.getElementById('num_squares_text');
          let num_squares = Number(num_squares_text.value);
          let mytext = "";
          for (let i = 0; i < num_squares; i++) {
            mytext += mysquare;
          }
          let contents = document.createTextNode(mytext);
          const mylabel = document.getElementById('mylabel');
          mylabel.textContent = ''; // set to empty string
          mylabel.appendChild(contents); // replace with squares
        }

        function init() {
          const draw_button = document.getElementById('draw_button');
          draw_button.addEventListener('click', handle_draw_button);
          /*
          const mylabel = document.getElementById('mylabel');
          let mytext = mysquare + mysquare;
          let contents = document.createTextNode(mytext);
          mylabel.appendChild(contents);
          */
        }
      </script>
   </head>
   <body>
     Enter number of squares:
     <input type="text" id="num_squares_text">
     <button id="draw_button">Draw</button><br>
     <label id="mylabel"></label>
   </body>
</html>

The new lines are lines 9-19. Line 9 just comments out the console.log debugging statement. Line 10 gets the reference to the input text box. Line 11 gets the value from that text box and also uses Number() to convert that value into a number.

Line 12 initializes a variable called mytext to be an empty string. The lines 13-15 use a for loop to concatenate the text for a white square on to mytext the correct number of times. Line 16 creates a TextNode from mytext.

Line 17 gets a reference to the <label> element. Line 18 sets the content of that <label> to an empty string. This is so when the new contents is appended to that <label>, this always gets appended to an empty string, not the previous string from the last time you hit the Draw button.

Optional exercise

Modify the code so that when you enter a number of squares, the squares show up with spaces in between like shown in the following screen shot.

exercise1 6