Two methods we will use a LOT are document.getElementById
and
document.querySelectorAll
. It's handy to
declare a shortcut to help us out. You may use the following in your JS
programs (these are exceptions to the rule of having description function
names):
function $(id) {
return document.getElementById(id);
}
function qsa(query) {
return document.querySelectorAll(query);
}
We will start using these in lecture examples!
In programs, we often want to repeat some behavior - what can we do to repeat some behavior N times? (loops!)
In simple Java/Python programs, there isn't usually motivation to delay code execution
On webpages with JavaScript, there is often motivation to delay or repeat behavior every X seconds
function startCountDown() {
let count = 10;
for (let i = 10; i > 0; i--) {
console.log(i + "...");
}
console.log("0!");
}
This prints a countdown to the console as soon as it's called. But what if we want to delay each line printed by 1 second?
Used to delay or set intervals for executing functions
method | description |
---|---|
setTimeout(responseFn, delayMS) | Arranges to call given function after given delayMS, returns timer id |
setInterval(responseFn, delayMS) | Arranges to call function repeatedly every delayMS ms, returns timer id |
clearTimeout(timerID)
clearInterval(timerID) |
Stops the given timer |
Both setTimeout
and setInterval
return an ID
representing the timer
window
has access to in order to manage the
page timers.
clearTimeout
/Interval
later
(e.g. when clicking a "stop timer" button)setTimeout
Example<button id="demo-btn">Click me!</button>
<span id="output-text"></span>
function initialize() {
$("demo-btn").addEventListener("click", delayedMessage);
}
function delayedMessage() {
$("output-text").innerText = "Wait for it...";
setTimeout(sayHello, 5000);
}
function sayHello() { // called when the timer goes off
$("output-text").innerText = "Hello!";
}
setInterval
Example<button id="demo-btn">Click me!</button>
<span id="output-text"></span>
let timer = null; // stores ID of interval timer
function repeatedMessage() {
timer = setInterval(sayHello, 1000);
}
function sayHello() {
$("output-text").innerText += "Hello!"
}
More details on timer
variable on slide below
timer
variableclearInterval/clearTimeout
or know if
we have a timer already running on our page.
clearInterval
Example<button id="toggle-btn">Start/Stop<button>
let timer = null; // stores ID of interval timer
function initialize() {
$("toggle-btn").addEventListener("click", toggleMessageInterval);
}
// 1. What does this function do?
function toggleMessageInterval() {
if (timer === null) {
timer = setInterval(sayHello, 1000);
} else {
clearInterval(timer);
timer = null; // 2. Why is this line important?
}
}
function sayHello() {
$("output-text").innerText += "Hello!"
}
function startCountDown() {
let count = 10;
for (let i = count; i > 0; i--) {
console.log(i + "...");
}
console.log("0!");
}
Recall that this function prints each line immediately (in order). If we want to output each line every 1 second (1000ms), what kind of timer should we use?
let timer = null;
function startCountDown() {
let i = 10;
timer = setInterval(function() {
console.log(i + "...");
i--;
}, 1000);
console.log("0!");
}
What's wrong here? (remember we want a 10 second countdown printed to the console)
let timer = null;
function startCountDown() {
let i = 10;
timer = setInterval(function() {
if (i === 0) {
console.log("0!");
} else {
console.log(i + "...");
i--;
}
}, 1000);
}
This is closer! But there's still something wrong...
Our timer won't stop when we reach 0!
let timer = null;
function startCountDown() {
let i = 10;
timer = setInterval(function() {
if (i === 0) {
clearInterval(timer);
timer = null;
console.log("0!");
} else {
console.log(i + "...");
i--;
}
}, 1000);
}
This is a working solution! When startCountDown
is called, we assign
a new interval to our timer and start a 1-second countdown at 10.
When we reach 0, we need to clear the interval from the window's tasks and set our timer to null to indicate when our timer is finished (if we want to start a new timer later).
function delayedMultiply() {
// 6 and 7 are passed to multiply when timer goes off
setTimeout(multiply, 2000, 6, 7);
}
function multiply(a, b) {
alert(a * b);
}
Any parameters after the delay are eventually passed to the timer function
Why not just write this?
setTimeout(multiply(6 * 7), 2000);
Many students mistakenly write ()
when passing the function
setTimeout(booyah(), 2000);
setTimeout(booyah, 2000);
setTimeout(multiply(num1 * num2), 2000);
setTimeout(multiply, 2000, num1, num2);
What does it actually do if you have the ()
?
Note: This is also a common bug with addEventListener
!
When you want to call a function after a specified delay in time, use
setTimeout
.
When you want to call a function repeatedly every X seconds, use
setInterval
(though you can also use setTimeout
recursively!)
For both types of timers, you'll need a variable with the timer id (returned
by both functions) to pass to clearTimeout
/clearInterval
when
you want to stop the delay/interval.
document.getElementyById(...)
document.querySelector(...)
document.querySelectorAll(...)
document.createElement(...)
(introduced now!)Methods in document and other DOM objects:
Name | Description |
---|---|
querySelector(selector) | returns the first element that would be matched by the given CSS selector string |
querySelectorAll(selector) | returns an array of all elements that would be matched by the given CSS selector string |
getElementsByName(name) | returns array of descendants with the specified name (mostly useful for accessing form controls) |
Use querySelectorAll
to highlight all paragraphs in the document:
<body>
<p>This is the first paragraph</p>
<p>This is the second paragraph</p>
<p>You get the idea...</p>
</body>
// get all DOM objects that are <p>
let allParas = document.querySelectorAll("p");
for (let i = 0; i < allParas.length; i++) {
allParas[i].classList.add("highlighted");
}
This is the first paragraph
This is the second paragraph
You get the idea...
Let's say we want to highlight all paragraphs inside of the section with ID 'address':
<p>This won't be highlighted!</p>
<div id="address">
<p>1234 Street</p>
<p>Seattle, WA</p>
</div>
We can use querySelectorAll
to return an array of all the
elements we want. What is the CSS query we would use to select all the
paragraphs we want? (#address p)
CSS Selector Mystery practice if needed: here and here and here
querySelectorAll
<p>This won't be highlighted!</p>
<div id="address">
<p>1234 Street</p>
<p>Seattle, WA</p>
</div>
let addrParas = document.querySelectorAll("#address p");
for (let i = 0; i < addrParas.length; i++) {
addrParas[i].style.backgroundColor = "yellow";
}
This won't be highlighted!
1234 Street
Seattle, WA
querySelectorAll
issues
Many students forget to write .
or #
in front of a class or
id
// get all buttons with a class of "control"
let gameButtons = document.querySelectorAll("control");
let gameButtons = document.querySelectorAll(".control");
querySelectorAll
returns an array, not just a single element;
you must loop over the results
// set all buttons with a class of "control" to have red text
document.querySelectorAll(".gamebutton").classList.add("hidden");
let gameButtons = document.querySelectorAll(".gamebutton");
for (let i = 0; i < gameButtons.length; i++) {
gameButtons[i].classList.add("hidden");
}
Q: Can I still select a group of elements using querySelectorAll
even if
my CSS file doesn't have any style rule for that same group?
(A: Yes!)
Use querySelector
to highlight the first paragraph in the document:
<body>
<p>This is the first paragraph</p>
<p>This is the second paragraph</p>
<p>You get the idea...</p>
</body>
// get all DOM objects that are <p>
let para = document.querySelector("p");
para.classList.add("highlighted");
This is the first paragraph
This is the second paragraph
You get the idea...