-
Notifications
You must be signed in to change notification settings - Fork 0
/
manipulating-the-dom.html
385 lines (324 loc) · 17.5 KB
/
manipulating-the-dom.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- Force IE to use its standard document rendering mode - I found this line at https://stackoverflow.com/questions/10975107/forcing-internet-explorer-9-to-use-standards-document-mode -->
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width">
<title>Manipulating the DOM | Jschool</title>
<link type="text/css" rel="stylesheet" href="css/style.css">
<link rel="shortcut icon" href="images/js-icon.png" type="image/x-icon">
</head>
<body>
<header>
<!-- Page header containing logo/site title, with a navigation bar
nested inside of it-->
<a href="index.html"><h1 id="header-logo">Jschool</h1></a>
<!-- navigation bar in the semantically nice nav element -->
<nav>
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="index.html#tutorial-section">Tutorials</a></li>
<li><a href="quizzes.html">Quizzes</a></li>
<li><a href="about.html">About</a></li>
</ul>
</nav>
</header>
<div id="tutorial-container" class="fade-in">
<section class="lead">
<h1>Manipulating the DOM</h1>
<p>The DOM is the Document Object Model - the way in which a HTML page can be represented in JavaScript objects.
This means that JavaScript can then be used to read data from these objects, and also to manipulate them. <a
href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model" target="_blank">A full
DOM reference is available here</a>, however this tutorial provides a simple introduction to simple
element selecting and manipulation, which ought to be more than enough to get started!</p>
</section>
<section>
<h2>Selecting Elements by ID</h2>
<p>The simplest way to get started with DOM element selection is to select by ID. You give the HTML element you
wish to select an ID value, and then use the DOM's document.getElementById("whatever-the-id-was") function
to select the object. An example of this (with associated HTML) is below...</p>
<!-- Code snipping to follow... no indentation inside of code tags because the pre tag forces them to be un-formatted, so indentation does not work! -->
<pre>
<code>
<html>
<head>
<title>DOM Test</title>
</head>
<body>
<p id="my-paragraph">This is a paragraph</p>
<script>
/* this JavaScript is ran after the paragraph above (that we're selecting) is rendered */
var paragraph = document.getElementById("my-paragraph");
/* paragraph now contains the p element we wanted to select, let's check... */
console.log(paragraph);
</script>
</body>
</html>
</code>
</pre>
<p class="top-tip">As noted in the code comments above, you should wait until the page elements are rendered
before selecting them. You can do this by placing your JavaScript in the page after the elements, or by some
more sophisticated methods which we'll discuss later on.</p>
</section>
<section>
<h2>A better way of selecting elements - QuerySelectors</h2>
<p>QuerySelectors provide a far more flexible way of selecting HTML elements from the DOM. Instead of using just
ID's, they allow you to use the same selectors as in CSS to select one or multiple matching elements from
the DOM. This means you can select all instances of a specific elements, specific class, or more complex
selectors such as direct child (e.g. div > p) - just like in CSS.</p>
<p>The relevant JavaScript methods are <a
href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector">document.querySelector()</a>
and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll">document.querySelectorAll()</a>.
</p>
<p>The major difference between these is that querySelector selects only ONE element (the first one it matches),
whereas querySelectorAll returns an array of ALL of the matched elements - making it far more useful. Both
return nil if no elements are matched. An example of these methods in action is below...</p>
<!-- Code snipping to follow... no indentation inside of code tags because the pre tag forces them to be un-formatted, so indentation does not work! -->
<pre>
<code>
<html>
<head>
<title>DOM Test</title>
</head>
<body>
<h1>A big heading</h1>
<p class="fancy-paragraph">This is a paragraph</p>
<p class="fancy-paragraph">This is another paragraph</p>
<p class="fancy-paragraph">And this is yet another paragraph</p>
<script>
/* this JavaScript is ran after the paragraph above (that we're selecting) is rendered */
/* select the one H1 heading... see how we're using the h1 selector - just like in CSS */
var heading = document.querySelector("h1");
/* check we got the heading... */
console.log("The heading is " + heading);
/* select all of the .fancy-paragraph's into an array... */
/* see how we're using the .fancy-paragraph selector -
just like in CSS - to select all instances of that class */
var paragraphs = document.querySelectorAll(".fancy-paragraph");
/* loop through our paragraphs... */
for (var i = 0; i < paragraphs.length; i++) {
/* get the paragraph from the array */
var currentParagraph = paragraphs[i];
/* let's log it too... */
console.log("Fancy paragraph " + String(i) + " is " + currentParagraph);
}
</script>
</body>
</html>
</code>
</pre>
<p class="top-tip">Whilst CSS selectors such as the direct child selector work with QuerySelectors, sadly the
CSS pseudo classes such as first-child don't, so consideration must be made for this.</p>
</section>
<section>
<h2>Getting and Setting Element's content</h2>
<p>One of the most important features that JavaScript provides to make web pages interactive is the ability to
get and set the content of elements.</p>
<p>Firstly, use the QuerySelectors described above to get the element, then, once the element is in a JavaScript
variable, JavaScript allows you to very simply and effectively get the text within via the .textContent
property - or set the text within by setting a new value to the .textContent property - as in the example
below.</p>
<p>To get and set raw HTML, simply replace .textContent with .innerHTML.</p>
<!-- Code snipping to follow... no indentation inside of code tags because the pre tag forces them to be un-formatted, so indentation does not work! -->
<pre>
<code>
<html>
<head>
<title>DOM Test</title>
</head>
<body>
<h1>A big heading</h1>
<p class="fancy-paragraph">This is a paragraph</p>
<p class="fancy-paragraph">This is another paragraph</p>
<p class="fancy-paragraph">And this is yet another paragraph</p>
<script>
/* lets practice some getting... */
/* select the one H1 heading... see how we're using the h1 selector - just like in CSS */
var heading = document.querySelector("h1");
/* check we got the heading... */
console.log("The contents of the heading is " + heading.textContent);
/* now lets practice some setting... */
/* select all of the .fancy-paragraph's into an array... */
var paragraphs = document.querySelectorAll(".fancy-paragraph");
/* loop through our paragraphs... */
for (var i = 0; i < paragraphs.length; i++) {
/* get the paragraph from the array */
var currentParagraph = paragraphs[i];
/* set the paragraph's content to be the number in the array that it's at... */
currentParagraph.textContent = String(i);
}
</script>
</body>
</html>
</code>
</pre>
<p>A video example of using QuerySelectors to get and set the content of HTML elements is below so you can
follow along... </p>
<div class="video-container">
<video controls>
<source src="videos/queryselectors-textcontents-tutorial.mp4" type="video/mp4">
Terribly sorry but it doesn't look like your web browser supports HTML5 video - please try another
browser (such as Google Chrome).
</video>
</div>
</section>
<section>
<h2>Styling elements with JavaScript</h2>
<p>Another important way in which elements can be made interactive with JavaScript is by changing their
style.</p>
<p>The DOM provides ways to add, remove and alter CSS styles - both in terms of individual style rules, and also
in terms of adding ID's and classes to elements, to style them differently.</p>
<p>The simplest way to modify styles is by using the .style property of elements - this property allows you to
change any CSS property simply by appending the property to .style - so for example, to change the
background colour of 'myElement', you'd call myElement.style.background-color = "rgb(20, 20, 20)"; on the
element you've retrieved (from a QuerySelector for example).</p>
<p>You can also style by adding classes or ID tags - for example, to add a class to 'myElement', you'd call
myElement.classList.add("newClass") (you can also first use the classList property - which is simply a
standard JavaScript array - to check which classes are currently applied to the element).</p>
<p>Additionally, you can add an ID to a selected element using its .id property - for example myElement.id =
"cool-unique-id";</p>
<p>An example of some simple and some more complex styling is below...</p>
<!-- Code snipping to follow... no indentation inside of code tags because the pre tag forces them to be un-formatted, so indentation does not work! -->
<pre>
<code>
<html>
<head>
<title>DOM Test</title>
<style>
.cool-text {
background-color: rgb(0, 255, 0);
color: rgb(255, 255, 255);
}
#littleish-heading {
font-size: 16pt;
font-weight: bold;
}
</style>
</head>
<body>
<h1>A big heading</h1>
<h2>A 'lil heading</h2>
<p>This is a paragraph</p>
<script>
/* let's change the heading colour... */
/* select the one H1 heading...*/
var heading = document.querySelector("h1");
/* set it's 'color' style attribute */
heading.style.color = "rgb(255, 0 ,0)";
/* now let's practice adding classes... */
var paragraph = document.querySelector("p");
/* add the cool-text class... */
paragraph.classList.add("cool-text");
/* now let's add an ID to the littler heading (h2) */
var smallHeading = document.querySelector("h2");
/* add the ID... */
smallHeading.id = "littleish-heading";
</script>
</body>
</html>
</code>
</pre>
</section>
<section>
<h2>Adding events with JavaScript</h2>
<p>The next stage of using JavaScript with the DOM to make HTML pages interactive is to add event listeners,
meaning that JavaScript functions can be called when certain things happen on the page (such as specific
elements being clicked or hovered over, etc.).</p>
<p>A full list of events is <a href="http://www.w3schools.com/jsref/dom_obj_event.asp">available here</a>, but
in this tutorial we'll be specifically focusing on adding 'on click' events - although the principle is much
the same for any type.</p>
<p>Firstly, you must select the element you wish to add the event to, and then set its .onclick property to a
function (remembering here that functions in JavaScript can be passed as variables!).</p>
<p>An example of the onclick listener being added is shown below...</p>
<!-- Code snipping to follow... no indentation inside of code tags because the pre tag forces them to be un-formatted, so indentation does not work! -->
<pre>
<code>
<html>
<head>
<title>DOM Test</title>
</head>
<body>
<p id="click-me">Click me!</p>
<script>
/* write the function to call when clicked */
function thisHappensOnClick() {
// here's the code to be executed on click...
console.log("You clicked!");
}
/* select the clicking element...*/
var clickable = document.querySelector("#click-me");
/* add the function to an onclick listener */
clickable.onclick = thisHappensOnClick;
</script>
</body>
</html>
</code>
</pre>
<p class="top-tip">Because JavaScript supports functions as variables, you can simply pass a function straight
to the onclick (e.g. myElement.onclick = function() { /* do stuff */ }) - this use of anonymous functions
stops many small functions being created just for button clicks etc.</p>
<p>A video example of adding anonymous event listeners is shown below...</p>
<div class="video-container">
<video controls>
<source src="videos/anonymous-event-listener-functions.mp4" type="video/mp4">
Terribly sorry but it doesn't look like your web browser supports HTML5 video - please try another
browser (such as Google Chrome).
</video>
</div>
</section>
<section>
<h2>On-load events</h2>
<p>A crucial kind of event to add is an onload event. This is because you cannot know for sure otherwise that
the HTML elements within the DOM have been rendered by the browser yet when your JavaScript is ran - and if
they haven't then your code won't be able to affect them.</p>
<p>This is clearly a major issue (and has been left out of previous Jschool examples to cut down on code
complexity, but may be why some examples don't work straight away).</p>
<p>To ensure that the DOM has been fully rendered before executing your script, you should add an event for the
window's .onload event handler (via window.onload). An example of this in action is below...</p>
<!-- Code snipping to follow... no indentation inside of code tags because the pre tag forces them to be un-formatted, so indentation does not work! -->
<pre>
<code>
<html>
<head>
<title>DOM Test</title>
</head>
<body>
<script>
/* define the function to call on DOM load*/
function loaded() {
// here's the code to be executed when the DOM has loaded...
console.log("The DOM has loaded - let the fun and games begin!");
}
/* add the function to the window's onclick listener */
window.onload = loaded;
</script>
</body>
</html>
</code>
</pre>
<p class="top-tip">Some legacy browsers may have poor support for onload events, which when it is such a crucial
event is a major issue - however, JavaScript frameworks - like we'll cover later on - can solve this to
improve older browser compatibility.</p>
</section>
</div>
<!-- Consistent footer containing links and other information -->
<footer>
<ul>
<li><a href="index.html">Home</a></li>
<li><a href="index.html#tutorial-section">Tutorials</a></li>
<li><a href="quizzes.html">Quizzes</a></li>
<li><a href="about.html">About</a></li>
<li><a href="credits.html">Credits</a></li>
</ul>
<p>© Dylan McKee 2015 - for Newcastle University.</p>
</footer>
<!-- linking JavaScript at the end for page load speed benefits.
Using RequireJS has meant that I only need to link one file into the actual
HTML, allowing my HTML to be semantically beautiful.
I can also load JavaScript in Async, which is ideal to speed up loading,
again thanks to RequireJS.
-->
<script data-main="js/main" type="text/javascript" src="js/lib/require.js" async></script>
</body>
</html>