Session 17: Changing Text on a Page with JavaScript Functions
Download this starter code to use for the opening exercise and the rest of the session.
Opening Exercise: Change Text on a Web Page
Last time, we learned how to write JavaScript code to change the content of a web page. Let's refresh our memory by changing the content of this page.
Write a script that changes the h2
heading
to "2024 is in the books. See you in 2025!".
Bonus challenge: if you have read
this week's reading,
add code to change the color of the new heading to red.
You may put your code in a script
element at the
bottom of the web page, or in the file
set-text.js,
which is loaded by the web page.
Solution
Here is
a possible solution.
The key is to use querySelector()
and
innerText
:
let element = document.querySelector('h2'); element.innerText = "2024 is in the books. See you in 2025!";
If we want to make the heading smaller, we can use the element's
innerHTML
property:
element.innerHTML = "<h5>2024 is in the books. See you in 2025!</h5>";
To change the color of text, we access the element's
style
attribute:
element.style.color = "red";
Recall that the DOM reveals an element's styling through the
data property style
, which is itself a JavaScript
object that contains all of the style properties as name/value
pairs. We write styling information differently in JavaScript
than in CSS, because we have to use JavaScript strings and
naming conventions.
Back to St. Ives
Last time, we learned about JavaScript objects, which contain data (known as properties) and methods. We then saw learned that our web browser exposes a web page to us as a JavaScript object, according to the domain object model (DOM). Together, we used these ideas to write a JavaScript script to change the content of a web page.
As we noted at the end of Session 16, all is good with our code until someone changes the story to include groups of 9 wives, sacks, cats, and kittens — or 11 or 5. Our code repeats the number 7 is several lines of code, and now we would have to change each one of them to the new number.
We can do better: we can write a function. Knowing how to write functions will be an essential skill for writing many of the scripts we want to be able to write. Let's learn about JavaScript now.
Functions
A function is
- a named* piece of code
- that groups statements together
- and makes code reusable.
* We'll expand on this later. Indeed, all three elements of this definition are subject to elaboration.
We have already seen a kind of function in the form of methods
associated with JavaScript's Math
,
String
, and console
objects.
We can define and call our own functions, too.
Here is the definition of a function to say 'hello' to the user of a web page:
function sayHello() { alert('Hello!'); }
alert()
is a built-in function like
prompt(),
which is introduced in Homework 7. alert()
is
useful for showing the user information that arises in the
course of an interaction.
We can execute code like this in the console, just like any other JavaScript. Once we have defined the function, we can use iy to execute the code it contains:
sayHello();
We often want to give some information to a function to help it do its job. Here is definition of a function that takes an argument:
function sayHello(name) { alert('Hello, ' + name + '!'); } sayHello('Alice');
When we give 'Alice' to the function, it assigns that value to
the variable name
before executing the function's
code.
We also frequently want a function to give us back an answer that it has computed. Here is definition of a function that returns a value:
function sayItTwice(somethingToSay) { return somethingToSay + ' ' + somethingToSay; } let message = sayItTwice('I have a lot to say!'); alert(message);
When a function returns a result, we can use that result in
whatever way is useful to us. Here, I assigned the value to
the variable message
so that I could use that
variable in another expression.
let message = sayItTwice('Rochelle'); sayHello(message);
makeURL(university)
.
The function receives a string as an argument. The string is a university's domain name.
The function returns the URL for university's website. For
example, UNI's domain is 'uni', so
makeURL('uni')
should return
"https://uni.edu".
Call your function with "uni" but also with a couple of other university's domains, such as "uiowa" and "iastate".
A Function for St. Ives
We can use these ideas to improve our script for the St. Ives page. First, we can group the calculations into a function that gives a name to the action as a whole:
function countTravelers() { let wives = 7; let sacks = 7 * wives; let cats = 7 * sacks; let kittens = 7 * cats; return wives + sacks + cats + kittens; }
Then we call the function instead of hardcoding the answer:
target.innerText = currentText + " " + countTravelers();
Now we can make our code work for other numbers of travelers. If the number of wives-sacks-cats-and-kittens can change, or if we want to give the user control over the number, then we can modify our function to take the number of wives et al. as an argument:
function countTravelers(count) { let wives = count; let sacks = count * wives; let cats = count * sacks; let kittens = count * cats; return wives + sacks + cats + kittens; } ... target.innerText = currentText + " " + countTravelers(7);
The result is this JavaScript file. Try it with 8 or 9 or 42. The answer updates correctly!
Functions will be very helpful to us as we write scripts. They will be essential as we learn how to interact with users using buttons, forms, and other input elements. They will be helpful as we write code that can be reused in different settings.
Exercise: A Function to Change Any Element's Text
Writing a function gives us the ability to use a group of statements repeatedly without having to duplicate the code. Let's put that power to use.
setText()
that:
- takes two arguments: a CSS selector and a string,
- finds the element using the given selector, and
- changes its text content to the given string.
set-text.js
and test it on
the web page from our opening exercise,
which loads the script file.
This function needs two pieces of information to do its job. A function can receive multiple arguments by separating their names with a comma:
function setText(selector, newText) {}
When we call the function, we also separate the arguments with a comma:
setText('p', 'REDACTED')
A Solution
Here is a possible solution.
function setText(selector, newText) { // find the HTML element let element = document.querySelector(selector); // change its text element.innerText = newText; } /* * test the function */ setText('p', 'REDACTED');
This function uses its first argument to select the HTML element:
function setText(selector, newText) { // find the HTML element let element = document.querySelector(selector); // change its text element.innerText = newText; } /* * test the function */ setText('p', 'REDACTED');
It uses its second argument as the new text for that element:
function setText(selector, newText) { // find the HTML element let element = document.querySelector(selector); // change its text element.innerText = newText; } /* * test the function */ setText('p', 'REDACTED');
When call the functions, the values we give it are assigned to those variables and used in the code.
function setText(selector, newText) { // find the HTML element let element = document.querySelector(selector); // change its text element.innerText = newText; } /* * test the function */ setText('th', 'Location');
With practice, this idea of taking code that we want to use, generalizing it to work for different values, and putting that code into a function will become more familiar.
A Comment on Comments
Recall that we learned about JavaScript comments last time. The JavaScript engine in the browser ignores comments. Their purpose is to make our code more understandable.
Comments can be
// one-line comments
in which case all characters to the end of the line are ignored. They can also be
/* they can span many lines */
as in CSS.
Use comments sparingly to explain your code. Whenever possible, use good variable names — then the code will explain itself.
Improvement #1: Ask the User for a Number
There are two weaknesses in nursery rhyme page at this point.
First, we hardcode a 7 (or 9, or 42) as a "magic number" in the
call to countTravelers()
. Why not let the user
tell us which number to use?
We can be accomplish using prompt()
, which is
introduced in
Homework 7.
prompt()
prompts the user, lets the user enter a
value, and returns the answer as a string. We need a number for
our calculation, so we ask JavaScript's
Number object
to convert it to a number before passing it to the function:
// Ask the user to enter a number and save the answer let usersChoice = prompt("How many wives are there?"); // Ask the Number class to convert usersChoice to a number let numberOfWives = Number(usersChoice); // Use the number as before target.innerText = currentText + " " + countTravelers(numberOfWives);
The prompt()
function is not an elegant way to
interact with the user. In the coming weeks, we will learn
other HTML and JavaScript tools we can use to seek user input.
Improvement #2: Change the Text to Match the Number
Our prompt lets the user control the number used in the rhyme, but now the text is incorrect! Even if the user enters a number different than 7, the text of the rhyme still says 7. Why not have our script modify the text to match the number?
I anticipated this task when I wrote the HTML for the web page.
Notice that all of the 7s in the text of the rhyme are wrapped
in a <span class="times"></span>
element. This gives us a "hook" for selecting the 7s and acting
on the text.
This creates a new challenge for us, though. We know how to
use querySelector(".times")
to select the
first of the 7s and set its inner text to the string
the user entered:
// change the text to match the user's number target = document.querySelector(".times"); target.innerText = usersChoice;
But there are four kinds of item to count, so 7 occurs four times in the text. How can we access the other three?
We could give a different class name to each occurrence and
target each separately. That would require us to repeat the
same two lines of code four times in order to select four
different classes. We
could try
CSS's :nth-of-type()
selector,
but that, too, would require us to repeat our text-changing code
four times, with minor tweaks.
JavaScript offers a better way. That path starts with a new query selector:
document.querySelectorAll('.times')
This method returns a new kind of object: a list containing all of the elements that match the query. JavaScript includes tools for working with objects of this sort, in particular for writing code that says "Do this action for each item in the list:". They require us to write... a function!
Working with lists is a topic for another day, but wouldn't it be nice to modify our script to do the job? Here is the code we need:
function changeText(e) { e.innerText = usersChoice; } // change the text to match the user's number targets = document.querySelectorAll(".times"); targets.forEach(changeText);
The result is this JavaScript file — and a fun nursery rhyme web page.
Now we know one thing that we will want to study in the coming
days. This will be one of our learning goals for the coming
week. Until then, though, let's stick with
querySelector()
and practice working with single
elements of the DOM.
Closing
Reading 9
Homework 7