{"componentChunkName":"component---src-templates-generic-template-js","path":"/lectures/lecture3-dom","webpackCompilationHash":"041090671d318979d692","result":{"data":{"markdownRemark":{"htmlAst":{"type":"root","children":[{"type":"element","tagName":"h2","properties":{"id":"the-document-object-model-dom"},"children":[{"type":"element","tagName":"a","properties":{"href":"#the-document-object-model-dom","ariaLabel":"the document object model dom permalink","className":["anchor"]},"children":[{"type":"element","tagName":"svg","properties":{"ariaHidden":"true","focusable":"false","height":"16","version":"1.1","viewBox":"0 0 16 16","width":"16"},"children":[{"type":"element","tagName":"path","properties":{"fillRule":"evenodd","d":"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"},"children":[]}]}]},{"type":"text","value":"The Document Object Model (DOM)"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"A web page (or document) is a set of (many) nested boxes, i.e. nested elements.\nThe DOM is a tree data structure representing the nested structure of the\ndocument. The boxes (HTML tags in our context) are nodes in the tree. "},{"type":"element","tagName":"a","properties":{"href":"https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model"},"children":[{"type":"text","value":"The DOM\nproperties and methods (the API) provide programmatic access to the tree to\naccess or change the document's structure, style or\ncontent."}]},{"type":"text","value":" "}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"More specifically JavaScript "},{"type":"element","tagName":"a","properties":{"href":"https://www.w3schools.com/js/js_htmldom.asp"},"children":[{"type":"text","value":"can"}]},{"type":"text","value":":"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ul","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Change all the HTML elements in the page"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Change all the HTML attributes in the page"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Change all the CSS styles in the page"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Remove existing HTML elements and attributes"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Add new HTML elements and attributes"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"React to all existing HTML events in the page"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Create new HTML events in the page"}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"The root of this tree is Document. It's child is the "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"html"}]},{"type":"text","value":" tag, whose children\nare the "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"head"}]},{"type":"text","value":" and "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"body"}]},{"type":"text","value":" (thus "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"head"}]},{"type":"text","value":" and "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"body"}]},{"type":"text","value":" are "},{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"siblings"}]},{"type":"text","value":"), etc. all the\nway down the leaf nodes containing text (or childless HTML elements). We can\n"},{"type":"element","tagName":"a","properties":{"href":"http://eloquentjavascript.net/13_dom.html#h_ShZPVipWw/"},"children":[{"type":"text","value":"programmatically\nnavigate"}]},{"type":"text","value":" the DOM\nusing tree concepts like parent, children, etc."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"As an example, navigate to the course webpage and open the "},{"type":"element","tagName":"a","properties":{"href":"https://developer.mozilla.org/en-US/docs/Tools/Web_Console/Opening_the_Web_Console"},"children":[{"type":"text","value":"Firefox web console"}]},{"type":"text","value":". Here we can\nexperiment \"live\" with the DOM API... Try some of the methods from the links\nabove, like "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"document.children"}]},{"type":"text","value":". For more detail about the tree-based API,\nreview the "},{"type":"element","tagName":"a","properties":{"href":"https://developer.mozilla.org/en-US/docs/Web/API/Node"},"children":[{"type":"text","value":"Node"}]},{"type":"text","value":",\n"},{"type":"element","tagName":"a","properties":{"href":"https://developer.mozilla.org/en-US/docs/Web/API/ParentNode"},"children":[{"type":"text","value":"ParentNode"}]},{"type":"text","value":" and\n"},{"type":"element","tagName":"a","properties":{"href":"https://developer.mozilla.org/en-US/docs/Web/API/ParentNode"},"children":[{"type":"text","value":"ChildNode"}]},{"type":"text","value":"\ninterfaces."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Some examples:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"> document"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Some built-in properties of "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"document"}]},{"type":"text","value":":"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"> document.head\n> document.body"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Alternately we can explore via the \"tree\" API, e.g."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"> document.children // only available on elements and only shows other elements\n> document.childNodes // shows all children, e.g. DOCTYPE declaration\n> document.lastChild.lastChild // navigate to the body element"}]}]}]},{"type":"text","value":"\n"},{"type":"comment","value":" \n\nShow a preview of this process\n1. Open up course home-page \n1. Open inspector\n1. Look at `document`, `document.body` and `document.body.children`\n\n "},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"It is more likely however, that we will find relevant elements based on their\ntype (e.g. "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"<h2>"}]},{"type":"text","value":"), id, CSS class, etc. We can do so with the\n"},{"type":"element","tagName":"a","properties":{"href":"https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector"},"children":[{"type":"text","value":"querySelector"}]},{"type":"text","value":"\nmethod that accepts CSS selector string as an argument."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Some example \"simple\" selectors: element type, #id, .class, ... Note that CSS\n"},{"type":"element","tagName":"a","properties":{"href":"https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors"},"children":[{"type":"text","value":"selectors"}]},{"type":"text","value":"\ncan be quite sophisticated (with combinations of type, class, etc.), but we are only going to scratch the surface here."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"> document.querySelectorAll(\"h3\")"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"We can also modify these elements via JavaScript:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"> document.querySelector(\"h2\").innerHTML = \"Class canceled today!\""}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"element","tagName":"em","properties":{},"children":[{"type":"text","value":"Note that in this example, we switched from "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"querySelectorAll"}]},{"type":"text","value":" to "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"querySelector"}]},{"type":"text","value":". The first returns a list, so we would have to iterate through to find the one we wanted or to change all of them. "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"querySelector"}]},{"type":"text","value":" on the other hand, returns the first instance found on the page, which may or may not be unique."}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Or in a more complex example, let's add some text to the sidebar menu. We do so by\ncreating a DOM node and inserting into the tree (with "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"appendChild"}]},{"type":"text","value":" or other\nrelated methods like "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"insertBefore"}]},{"type":"text","value":", "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"replaceChild"}]},{"type":"text","value":", etc.). "}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"> const elem = document.querySelector(\".sidebar\");\n> const annc = document.createTextNode(\"Run away!\");\n> elem.appendChild(annc);"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"We can restyle elements using similar tricks:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"> document.querySelector(\".sidebar\").style.background = \"red\";"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"JavaScript uses an event listener model for handling interaction.  If you want\nan element to respond to an event, e.g. a \"click\" you add an event handler to\nthe element. The handler is a function you would like to be invoked when the\nevent happens (i.e. a callback). We can do this generally with "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"addEventListener"}]},{"type":"text","value":",\nbut there are also older more specific functions for registering event\nhandlers, e.g. "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"onclick"}]},{"type":"text","value":", "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"onkeydown"}]},{"type":"text","value":", etc. that are widely used (we will use\n"},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"onclick"}]},{"type":"text","value":" extensively with React). "}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"> elem.onclick = (evt => alert(\"An emergency!\"));"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"with "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"addEventListener"}]},{"type":"text","value":":"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"div","properties":{"className":["gatsby-highlight"],"dataLanguage":"text"},"children":[{"type":"element","tagName":"pre","properties":{"className":["language-text"]},"children":[{"type":"element","tagName":"code","properties":{"className":["language-text"]},"children":[{"type":"text","value":"> elem.addEventListener(\"click\", evt => alert(\"Another emergency!\"))"}]}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"h2","properties":{"id":"motivating-example-a-rgb-color-picker"},"children":[{"type":"element","tagName":"a","properties":{"href":"#motivating-example-a-rgb-color-picker","ariaLabel":"motivating example a rgb color picker permalink","className":["anchor"]},"children":[{"type":"element","tagName":"svg","properties":{"ariaHidden":"true","focusable":"false","height":"16","version":"1.1","viewBox":"0 0 16 16","width":"16"},"children":[{"type":"element","tagName":"path","properties":{"fillRule":"evenodd","d":"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"},"children":[]}]}]},{"type":"text","value":"Motivating Example: A RGB color picker"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"We will create a RGB color picker similar in spirit to this\n"},{"type":"element","tagName":"a","properties":{"href":"https://www.w3schools.com/colors/colors_rgb.asp"},"children":[{"type":"text","value":"example"}]},{"type":"text","value":", with three sliders\n(R, G and B) that control a color swatch."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"We will eventually demonstrate many of APIs we discussed today, but let's start\nwith a simple implementation in which we have statically created all of the\nHTML elements, i.e. the swatch and sliders. The role for JavaScript is to\nrespond to "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"oninput"}]},{"type":"text","value":" events for the slider input element by updating the color,\nspecifically the CSS\n"},{"type":"element","tagName":"a","properties":{"href":"https://developer.mozilla.org/en-US/docs/Web/CSS/background"},"children":[{"type":"text","value":"background"}]},{"type":"text","value":"\nproperty, and the color components numeric value."}]},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"To do so, we will need to:"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"ol","properties":{},"children":[{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Obtain the DOM elements for the corresponding HTML elements (the swatch\n"},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"<div>"}]},{"type":"text","value":", slider "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"<input>"}]},{"type":"text","value":"s, value "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"<span>"}]},{"type":"text","value":"s) with "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"getElementById"}]}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Create a callback function that updates the swatch background color and the\nnumeric values"}]},{"type":"text","value":"\n"},{"type":"element","tagName":"li","properties":{},"children":[{"type":"text","value":"Bind the callback to the slider's "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"oninput"}]},{"type":"text","value":" event. Note that we purposely\nchoose this event instead of "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"onchange"}]},{"type":"text","value":" (the two\n"},{"type":"element","tagName":"a","properties":{"href":"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range"},"children":[{"type":"text","value":"choices"}]},{"type":"text","value":"\nfor "},{"type":"element","tagName":"code","properties":{},"children":[{"type":"text","value":"<input type=\"range\">"}]},{"type":"text","value":". The latter only \"fires\" when the change is\ncommitted by the user, i.e. they release the mouse, not for all changes to\nan input)."}]},{"type":"text","value":"\n"}]},{"type":"text","value":"\n"},{"type":"comment","value":" \nObtain the DOM elements\n\n    const colorBox = document.getElementById('color-swatch');\n    const colors = ['r','g','b'];\n\n    const labels = colors.map((color) => {\n    return document.getElementById(`value-${color}`);\n    });\n\n    const sliders = colors.map((color) => {\n    return document.getElementById(`slider-${color}`);\n    });\n\nCreate a callback function that updates the swatch\n    const update = function() {\n        colorBox.style.background =\n          `rgb(${sliders[0].value}, ${sliders[1].value}, ${sliders[2].value})`;\n        sliders.forEach((slider, index) => labels[index].innerHTML = slider.value);\n    };\n\nBind the `oninput` methods of the sliders to the callback\n    sliders.forEach((slider) => slider.oninput = update);\n\nCall the `update()` function to make the sliders and the swatch agree initially.\n    update(); \n    \n    "},{"type":"text","value":"\n"},{"type":"element","tagName":"p","properties":{},"children":[{"type":"text","value":"Knowing that we can create HTML elements dynamically, let's DRY up our solution\nby creating the picker dynamically. Doing so is the focus of today's "},{"type":"element","tagName":"a","properties":{"href":"/~candrews/classes/cs312-f19/practicals/practical02-color-picker.html"},"children":[{"type":"text","value":"practical\nexercise"}]},{"type":"text","value":"."}]}],"data":{"quirksMode":false}},"frontmatter":{"path":"/lectures/lecture3-dom","title":"Lecture 3 - JS and the DOM","name":"Lecture 3 - DOM"},"parent":{"__typename":"File","id":"97710cc8-c8ca-58f0-9a1f-c89d10bd0f11","name":"lecture3-dom","modifiedTime":"Sep 17 2019 03:40"}}},"pageContext":{"isCreatedByStatefulCreatePages":false}}}