this
this.fieldName // access field
this.fieldName = value; // modify field
this.functionName(parameters); // call method
All JavaScript code actually runs inside of an object
By default, code runs in the global window
object (so this === window
)
window
The this
keyword refers to the current object
window.onload = function() {
document.getElementById("textbox").onmouseout = booyah;
};
function booyah() { // booyah knows what object it was called on
this.value = "booyah";
}
Event handlers attached unobtrusively are bound to the element
Inside the handler, that element becomes this
The elements of a page are nested into a tree-like structure of objects
The DOM has properties and methods for traversing this tree
innerHTML
HackingWhy not just code this way?
function slideClick() {
document.getElementById("main").innerHTML += "<p>A paragraph!</p>";
}
Imagine that the new node is more complex:
function slideClick() {
document.getElementById("main").innerHTML += <p style='color: red; " +
"margin-left: 50px;' " + "onclick='myOnClick();'>" +
"A paragraph!</p>";
}
// create a new <h2> node
let newHeading = document.createElement("h2");
newHeading.innerHTML = "This is a heading";
newHeading.style.color = "green";
Name | Description |
---|---|
document.createElement("tag") | creates and returns a new empty DOM node representing an element of that type |
document.createTextNode("text") | creates and returns a text node containing given text |
Merely creating an element does not add it to the page
You must add the new element as a child of an existing element on the page...
let p = document.createElement("p");
p.innerHTML = "A paragraph!";
document.getElementById("main").appendChild(p);
Every DOM element object has these methods:
Name | Description |
---|---|
appendChild(node) | places the given node at end of this node's child list |
insertBefore(new, old) | places the given node in this node's child list just before old child |
removeChild(node) | removes the given node from this node's child list |
replaceChild(new, old) | replaces given child with new nodes |
How would we do each of the following in JavaScript code? Each involves modifying each one of a group of elements...
ul
list with id of 'tas' to have a gray background
Methods in document and other DOM objects:
Name | Description |
---|---|
getElementsByTagName(tag) | returns array of descendents with the given tag, such as "div" |
getElementsByName(name) | returns array of descendents with the specified name (mostly useful for accessing form controls) |
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 |
Highlights all paragraphs in the document:
let allParas = document.querySelectorAll("p");
for (let i = 0; i < allParas.length; i++) {
allParas[i].style.backgroundColor = "yellow";
}
<body>
<p>This is the first paragraph</p>
<p>This is the second paragraph</p>
<p>You get the idea...</p>
</body>
This is the first paragraph
This is the second paragraph
You get the idea...
Highlight all paragraphs inside of the section with ID 'address':
let addrParas = document.querySelectorAll("#address p");
for (let i = 0; i < addrParas.length; i++) {
addrParas[i].style.backgroundColor = "yellow";
}
<p>This won't be highlighted!</p>
<div id="address>
<p>1234 Street</p>
<p>Seattle, WA</p>
</div>
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; must loop
over the results
document.querySelector
returns just the first element that matches, if
that's what you want
// set all buttons with a class of "control" to have red text
document.querySelectorAll(".gamebutton").style.color = "red";
let gameButtons = document.querySelectorAll(".gamebutton");
for (let i = 0; i < gameButtons.length; i++) {
gameButtons[i].style.color = "red";
}
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!)
window.onload = function() {
document.getElementById("clickme").onclick = biggerFont;
};
function biggerFont() {
let button = document.getElementById("clickme");
let size = parseInt(button.style.fontSize);
button.style.fontSize = (size + 4) + "pt";
}
The style property lets you set any CSS style for an element
A catch: you can only use this to read styles set in the html
or with the DOM .style
. You cannot read css properties from this.
window.getComputedStyle(element).propertyName;
function biggerFont2() {
let button = document.getElementById("clickme2");
let size = parseInt(window.getComputedStyle(button).fontSize);
button.style.fontSize = (size + 4) + "pt";
}
getComputedStyle
method of global window
object accesses existing styles
The following example attempts to add 100px to the top of main
, but fails.
Consider the case when main
has top
set to "200px". Then
this code would update style.top
to be the invalid value of "200px100px"
let main = document.getElementById("main");
main.style.top = window.getComputedStyle(main).top + 100 + "px";
A corrected version:
main.style.top = parseInt(window.getComputedStyle(main).top) + 100 + "px";
function highlightField() {
// turn text yellow
let text = document.getElementById("text");
if (!text.className) {
text.className = "highlight";
} else if (text.className.indexOf("invalid") < 0) {
text.className += "highlight"; // awkward
}
}
JS DOM's className
property corresponds to HTML class
attribute
Somewhat clunky when dealing with multiple space-separated classes as one big string
classList
function highlightField() {
// turn text yellow
let text = document.getElementById("text");
if (!text.classList.contains("invalid")) {
text.classList.add("highlight");
}
}
classList
collection has methods add
, remove
,
contains
, and toggle
to manipulate CSS classes
Similar to existing className
DOM property, but don't have to manually
split by spaces
function slideClick() {
let bullet = document.getElementById("removeme");
bullet.parentNode.removeChild(bullet);
}
An odd idiom: obj.parentNode.remove(obj)
This is a paragraph of text with a link in it.
Element Nodes (HTML tag)
Text Nodes (text in a block element)
Attribute Nodes (attribute/value pair)
Every node's DOM object has the following properties:
Name(s) | Description |
---|---|
firstChild, lastChild | start/end of this node's list of children |
childNodes | array of all of this node's children |
nextSibling, previousSibling | neighboring nodes with the same parent |
parentNode | the element that contains this node |
Complete list of DOM node properties
Browser incompatibility information (IE6 sucks)
This is a paragraph of text with a
link.
This is a paragraph of text with a
link.
Q: How many children does the div
have?
A: 3
<p>
Q: How many children does the paragraph have? The a
tag?