Simple HTML with JavaScript

Using JavaScript with a HTML document

Using CodeSandbox for web programming

We are going to use CodeSandbox to start our programming adventure. Using CodeSandbox will allow us to get some experience with programming, even if we only have a simple computer like a low end Chromebook. As long as you have a connection to the Internet, we can get some real practice.

Although CodeSandbox makes it easy to start programming, you can still create complex projects using CodeSandbox. Also, if you have a suitable computer, it will be worth your time to learn how to set it up so that you can write the same kind of program without CodeSandbox. Steps on a way to do this can be found in the Intermediate part of this website.

Creating a new sandbox

Login to your CodeSandbox account. On the upper right, click on the + Create button to create a new sandbox.

create sandbox

Select the JavaScript template:

select javascript template

In the image above, note that the JavaScript template shows up twice in the Recently used area. You can click on any of those, as they will bring up the same template.

Here is what you will see next. You can choose the name of your sandbox. I changed my name to "simple html with javascript". Also, I have selected the Sandbox option, not the Devbox option. We want to use the Sandbox option as this runs on the browser.

configure sandbox

This will create a default sandbox based on the JavaScript template. If you look at the next screen shot, you will see that I have installed a couple of extensions. Actually, a number of extensions are displayed, but most of them were preinstalled.

extensions

Click on the icon that looks like four squares with the upper right square moved up and out. This is how you manage Extensions on the editor. This is the Visual Studio Code editor for browsers. The only extensions that I added are JavaScript-Essentials and Toggle Light/Dark Theme. The JavaScript-Essentials helps to find and fix errors in the JavaScript code. The Toggle Light/Dark Theme extension is used to toggle between a light and dark theme. I like to use the light theme, and that is what you will see through these lessons.

Looking at the important files

The next screen shot shows what the sandbox looks like in Explorer mode. This is the mode that we will be using nearly all the time. In Explorer mode, you can see a listing of all the important files located in the src folder. I have the index.html file selected, so in the middle panel you can see the contents of index.html. In the panel on the right, you can see what the resulting web page would look like in a browser.

view of sandbox

There are three files in the src folder: index.html, index.mjs and styles.css. For this lesson we will be focused on index.html and index.mjs.

HTML (Hypertext Markup Language) is a text-based language that gives structure to a web page and controls how things are displayed on that web page. When we are talking about web pages, the markup refers to the HTML used for that page. HTML is not a programming language. Instead, HTML contains the markup used by a browser to properly process the contents of the page for display. So, while HTML code is not a program, it is used by a program (the browser) to control what the page looks like.

So, the file index.html contains the markup for the web page.

The index.mjs file is a JavaScript file. JavaScript is the only programming language that can directly manipulate the contents of a web page. Since so many things are web-based, you can easily see why JavaScript is such an important language.

The extension .mjs is used for JavaScript files that conform to the ECMAScript Modules specification. You will see many JavaScript files that have the .js extension. That extension is often used to differentiate them from the .mjs files, because the .js files are often using the older CommonJS modules. The ECMAScript Modules specification is preferred and recommended by most JavaScript programmers who work with Node.js (a server-side form of JavaScript). Nevertheless, you will see some programmers using the .js extension even when they are using ECMAScript Modules. But, the .mjs extension is used to require that the more modern ECMAScript Modules specification is used. For these lessons, we will use .mjs files, as this is the more modern approach. However, you will definitely encounter JavaScript code that forces you to use the older CommonJS modules specification.

We will go over a comparison of the ES Module format vs the CommonJS format in some later lessons. For now, just remember that index.mjs is the file with the JavaScript code.

It is certainly possible to put both HTML and JavaScript code into a single .html file. You can find many examples of this on the Web. But, for these lessons we will keep them in separate files as this helps to keep the project organized.

Modifying index.html (the markup)

The first thing we will do is modify the index.html file. The file from the template is a reasonable start, but we want to make a few changes. Here is the new version of index.html

index.html
<!DOCTYPE html>
<html>
  <head>
    <title>JavaScript Sandbox</title>
    <meta charset="UTF-8" />
    <script src="./index.mjs" type="module"></script>
  </head>

  <body>
    <h1>Simple HTML with JavaScript</h1>
  </body>
</html>

The modified or new lines are 6 and 10. Line 6 shows the <script> element moved from the <body> up into the <head> section. This is my personal preference as I like to have only HTML markup inside the <body> element. Line 10 has been modified to replace the <div id="app"> element with a simple <h1> (heading1) element. Note that these changes will mess up the preview of the page, because we need to modify index.mjs. But, before we get to that, let’s make some observations on index.html.

Line 1 is a declaration that tells the browser to treat this HTML file as a HTML5 document. There were some important changes and additions made when they came up with the new version of HTML, i.e. HTML5. So, it is important that you make this declaration as the very first line of any HTML document we work on.

Lines 2 - 12 define the <html> element. It begins with the start tag on line2, and ends with the end tag on line 12. Most HTML elements have a start tag and an end tag. These tag names are predefined in HTML. So, you cannot just make up your own tag names. You should eventually learn about the important tags in HTML, but we will just stick with the ones we used in this file for now. Note that the end tag has the name of the element preceded with a /. So, <html> is the start tag, and </html> is the end tag.

Lines 3-7 define the <head> element. The <head> element is defined above the <body> element. Line 4 defines an optional <title> element. This specifies the text that shows up in the title bar of the browser, when the page is opened in a browser. The Preview in the CodeSandbox editor does not show the title. Line 5 specifies the character set to use when the browser is reading in the text on the page. The charset UTF-8 is the most commonly used character set, and we will use that just about all the time. This is a good character set to use as it can handle just about any character from any writing system. In addition, using the UTF-8 encoding can prevent the injection of harmful data that an attacker might use.

Line 6 will include the code from the file index.mjs to be used by this page. Note that the src attribute is set to ./index.mjs. The ./ is a way to specify that the file is in the same directory as the file that is doing the including. This type of notation is very important, because you will eventually run into cases where you have files that are not all in the same directory (folder). When you use a JavaScript file with the .mjs extension, you must specify the type attribute for the <script> as being module. This will force the browser to treat that JavaSript file as using the ECMAScript Modules (ES Modules) specification.

Line 6 shows an element, the <script> element, that uses attributes in the start tag. These attributes are properties that modify the usage of that element. In this particular case, the src attribute specifies the file to be included, and the type attribute (being module) specifies that the script is using the ES Modules format. Note that attributes are only used in the start tag. That is, end tags don’t contain attributes.

Lines 9-11 define the <body> element. This is where all the HTML markup for the part of the page that is displayed in the main window of the browser. I try to keep the <body> element free of any JavaScript code. Line 10 has replaced the original <div> element with a <h1> element. The <h1> (Heading1) element is a title that uses the largest size by default. Technically, there should only be one <h1> element in a document. Other headings would include <h2>, <h3>, <h4>, <h5> and <h6>. As the number gets larger, the smaller the default size of the heading. A heading element will have a blank line above and below it when displayed in the browser.

Modifying index.mjs (the JavaScript code)

As you have probably noticed, the Preview is showing an error. This is because we need to modify index.mjs. In the Explorer, click on the file index.mjs inside of the src folder to begin editing it. Here is the new version of index.mjs:

index.mjs
import "./styles.css";

if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", init);
} else {
  init();
}

function init() {
  console.log("init called");
}

The new lines are 3-7 and 9-11. Basically, we have replaced everything except the first line. Lines 3-7 define what is called a selection statement in programming. Although this looks like a number of lines, those lines represent a single selection statement. A selection statement allows the program to select only certain lines of code to be ruun, depending on the value of a test condition. This is why selection statements are commonly referred to as conditional statements. This particular selection statement is what is called an if statement.

One of the most important things that a JavaScript programmer must get used to, is that the JavaScript code must not start executing until the page is rendered by the browser. The reason for this, is that JavaScript is often used to manipulate some HTML elements on the page. To perform this manipulation, the JavaScript code needs to have a way of specifying exactly which element is being affected. This means two things. First, that element must have already been rendered, and second, the element must have something that makes that element selectable.

JavaScript modifies HTML elements on a page. Those elements must already be rendered before the JavaScript executes. In addition, those elements must be selectable either by and id or a class. When you want a single element to be selected, then that element should have an id attribute. This is because by convention id attributes are unique. On the other hand, if multiple elements must be selected at once, then those elements should have the same class attribute, as many elements can share the same class attribute.

Getting back to our code, this particular if statement represents two cases. The first case starts on line 3 and ends on line 5. This first case is executed if the test condition document.readyState === "loading" is true. In terms of what is physically happening, this case will be true if the HTML elements in the body are still being rendered. The second case is the else clause that starts on line 5 and ends on line 7. An else clause can only exist as part of an if statement. That is why the else is referred to as a clause not a statement. If you understand how else works, you will see why this has to be the case. The else case matches anything that is not previously matched. So, if the first case (document.readyState === "loading") is not true, then the else case is executed.

Let’s dig into more of the details. If the document is still being rendered (still loading), then line 4 will be executed. Line 4 adds something called an Event Listener that specifies that a function be called when that event being listened for occurs. In this case, the event that is being listened for the DOMContentLoaded event. That event occurs when the HTML elements in the <body> are completely rendered. When that event occurs, the init() function is called. In any programming language, you need to set a start point for the program to start running. A common way to do this in JavaScript programming, is to make a function called init() that provides that start point.

On the other hand, if the document is already rendered (the else case), then the init() function is called. So, in either case the init() function is called. By making init() the function that is called when the DOMContentLoaded even occurs, this if statement ensures that init() will be called after the page is fully rendered, and that init() marks the starting point of the JavaScript execution.

If all these details about lines 3-7 of the code seem overwhelming to you as a beginner, don’t worry about this so much. Just understand that those lines can go at the beginning of the JavaScript code, and will ensure that the init() function is the first thing that executes, and that the init() function will execute only after the page is loaded.

Lines 9-11 define the init() function. In this case, there is only one line of instruction and that is line 10. The console.log() function will print the argument (whatever is in the parentheses) to the console. In JavaScript the console is a place where you can send output. If this where a program running in a real browser, the console is displayed as part of the Dev Tools. You would have to hit F12 or right-click on the window and select Inspect to bring up the Dev Tools. But, in CodeSandbox, you can display the console in the Preview area by clicking on the console (console icon) button. The following screen shot shows how this works:

showing console

As you can see, the message output from the console.log() function is displayed in the console.

Using calls to console.log() is the most important technique in writing JavaScript code. This is how you can "see" what is going on inside the program. If you add calls to console.log() to ensure that variables and objects are what you think they are, this will help you to write programs correctly and more efficiently. You can always comment out those console.log() calls, once you have verified that things work as they should.

In addition, using console.log() calls can be a good way to track down bugs when writing code as well.

Using <input> elements

Let’s add some <input> elements into our markup. One of the ways you can make your program interact with the user, is to use input from the user to modify what is displayed by your program. The HTML <input> element is one of the best simple ways to gather user input. The <input> element has many possible types of which several are commonly used.

A good introduction to using the <input> element can be found at w3schools.com form input types. That page shows many more types than you might ever use, but it is worth your time to look these over as they might come in handy.

Text boxes

For this lesson, let’s use text boxes as they are commonly used. This means using elements that look like this:

<input type="text" id="namebox">

There are other attributes that can be used with text boxes (such as size), but this is good minimum way to set a text box up. That is, you give it a type="text" attribute and an id attribute. You choose the value of the id attribute in a way that helps remind you what that text box is being used for.

Let’s add some text boxes to our markup. Here is the new version of index.html:

index.html
<!DOCTYPE html>
<html>
  <head>
    <title>JavaScript Sandbox</title>
    <meta charset="UTF-8" />
    <script src="./index.mjs" type="module"></script>
  </head>

  <body>
    <h1>Simple HTML with JavaScript</h1>
    num1:
    <input type="text" id="num1box" size="7" />
    num2:
    <input type="text" id="num2box" size="7" />
    <button id="add_button">Add</button>
    <br /><br />
    Result:
    <input type="text" id="resultbox" size="8" />
  </body>
</html>

The new lines are 11-18. Line 11 is just some text that serves as a prompt for the next input box. Line 12 creates an input text box with an id="num1box" attribute. The size attribute is used here to shrink the default size of the text box so that it does not take up too much space. Line 13 is the prompt for the next input box. Line 14 creates an input text box with an id="num2box" attribute that also has a size of 7. Line 15 creates a <button> element that has an id="add_button" attribute. The text in between the start tag and the end tag of the <button> element will be the text displayed on the button. Line 16 puts in a couple of <br /> (break) elements that forces the output to go to the next line. This will leave a blank line before the next element. Line 17 is a label for the last text box. Line 18 creates an input box where the result will be displayed. After entering these lines in, you can see in the Preview what this looks like. In addition to the preview of the body, look at the Elements tab being displayed below.

input elements added

So, as you can see, besides the Console, the Elements tab is also useful. By glancing at the Elements we can see the names of the id attributes. That will be useful when we modify the JavaScript code.

Modifying index.mjs (the code)

Let’s start to modify index.mjs. We will do this in small increments to try to make it easier to grasp the important points. We’ll start by making it so that we can respond to the user clicking on the Add button. Here is the new version of index.mjs:

index.mjs
import "./styles.css";

if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", init);
} else {
  init();
}

function handleAdd() {
  console.log("handleAdd called");
}

function init() {
  const add_button = document.getElementById("add_button");
  add_button.addEventListener("click", handleAdd);
}

The new lines are 9-11 and 14-15. Line 14 gets a reference to the add button. This is needed so that on line 15 we can assign the handleAdd() function to be the function that is called when the add button is clicked. So, on line 15, the event that we are responding to is the 'click' event that occurs when a user clicks on that button. The second argument to the addEventListener() function is the name of the function that is called when that event occurs. This is a very important set of lines to understand, as this is one of the key ways that JavaScript can make a web page dynamic.

Lines 9-11 define the handleAdd() function. At this point, all this function does is print to the console 'handleAdd called'. This will be our way of testing that the event handling is working so far.

The following partial screen shot shows the Preview screen displaying the Console:

handleAdd called

Incremental Development

Note that we only added a few lines of code before testing to see if what we added works correctly. The method of adding only enough code so that you can test, testing, and then continuing if the code works, is called Incremental Development. This is probably the most important programming technique there is. This applies to every programming language and practically every programming project.

I actually know a guy who I went to graduate school with. He started working for a company and within a year’s time, he taught himself to program in the C language, and wrote the operating system used to control some of the first parallel processing computer systems ever. He told me that the key to his success was using incremental development. Well, this guy is super smart and super hard working. But, he would not exaggerate how useful incremental development is, since he is also super honest. Ever since hearing that, I try to always practice incremental development and always tried to encourage my students to do this as well.

Reading and processing the input

What we are trying to do here is gather the user input for num1 and num2 and then add those numbers together. Then, we want to display the result in the result text box. This means we need to modify the handleAdd() function in index.mjs. Here is the modified version:

index.mjs
import "./styles.css";

if (document.readyState === "loading") {
  document.addEventListener("DOMContentLoaded", init);
} else {
  init();
}

function handleAdd() {
  const num1box = document.getElementById("num1box");
  const num2box = document.getElementById("num2box");
  const num1text = num1box.value;
  const num1 = Number(num1text);
  const num2 = Number(num2box.value);
  const result = num1 + num2;
  const resultbox = document.getElementById("resultbox");
  resultbox.value = result;
}

function init() {
  const add_button = document.getElementById("add_button");
  add_button.addEventListener("click", handleAdd);
}

The new lines are 10-17. Line 10 gets a reference to the text box for num1. Line 11 does the same thing for the text box for num2. Line 12 gets the user input inside of the text box for num1. Line 13 uses the Number() function to convert that user input (which is text, not a number) into a number. Line 14 does what is done on line 12 and line 13 for the text box for num2. Normally, I would combine line 12 and line 13 into one instruction just as on line 14. But, we do this here only to emphasize the that value of a text box is always a string (text), not a number. So, if you need for that value to be treated as a number, you must convert it using the Number() function.

Line 15 adds the two numbers and stores this in the constant result. Line 16 gets a reference to the result text box, so that on line 17 we can place the result into that text box.

The next partial screen shot shows the result of inputting in some numbers and pressing the Add button:

numbers added

What does const mean?

If you have done any programming before, you may know something about variables. We use variables to store data, to make it easier to manipulate that data. In JavaScript, we declare variables using either the keyword const or the keyword let. We use const when the value being referred to does not need to be changed within the scope of that const. So, you can think of the declaration const being used for things that don’t have to be changed within the scope of those things. The scope of a const or a let is the curly braces ({ }) within the const or let is defined. Here is the code for our handleAdd() function from index.mjs:

function handleAdd() {
  const num1box = document.getElementById("num1box");
  const num2box = document.getElementById("num2box");
  const num1text = num1box.value;
  const num1 = Number(num1text);
  const num2 = Number(num2box.value);
  const result = num1 + num2;
  const resultbox = document.getElementById("resultbox");
  resultbox.value = result;
}

Everything here is declared as const. That is because the values that they point to don’t change within this function. Since they are all declared within the handleAdd() function, that is the scope of those const references. This can get a little tricky because you can declare a reference to an object as const. The values within that object can change, but the reference to the object being declared this way does not change.

If you know something is going to change, then you should declare it as let. You could define everything as let and not use const, but this is not considered best practice. This is because a reference to an object should not change, and so should be declared as const. Think of how a problem might arise if you have two different variables referring to the same object. This can lead to difficulties in understanding the code and maintaining it. So, any reference to an object, should be declared as const.

Summary

  • We kept our JavaScript code in the file index.mjs and our HTML markup in the file index.html. So, we kept the markup separate from the JavaScript code. This is a good practice in general. But, be aware that many examples online will show these combined into just one HTML file.

  • We learned about Incremental Development and used it to develop our code in small pieces that could be tested before going on to add more code.

  • We saw that for JavaScript code to interact with a HTML element, that element should have a unique id attribute.

  • We used the element.addEventListener() function to associate a function that will be called when that event occurs. So far, the two events that we have dealt with are the DOMContentLoaded event (that occurs when the page has been loaded) and the click event that occurs when an element has been clicked on .

  • We learned to use the Console area in the Preview to see the output from console.log() statements. Also, we learned how we can use console.log() to test our code as we develop increments of the code.

  • We learned that <input type="text"> elements will have a value that is a string (text), so it must be converted into a number using the Number() function.