DOM - Document Object model

DOM: Document Object Model. Before learning Javascript, we need to learn DOM. 

A good link here on digitalocean. Go thru the whole series, very neatly explained. You should not need to look anywhere else, as it's comprehensive.

https://www.digitalocean.com/community/tutorial_series/understanding-the-dom-document-object-model

Mozilla docs are also a very good source for anything internet/browser related. sometimes they do appear more technical for beginners, but they do start with basics:

https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model

We already read about html syntax, and saw that it contains various tags, many of them nested inside each other. XML, SVG documents are also similar to html where they have various tags. These kind of documents can easily be represented by a tree.  DOM is that tree rep of this document. This is how browsers store html pages in memory, so that it's easier for other pgm languages to access this html doc, as well for the browser to carry out various operations on this html doc. If browsers or any programming language worked directly on html doc, it would be very inefficient to parse it and collect all reqd info about the doc every time. DOM is just a more efficient rep of that same HTML page, with all the info in it in a tree form. The DOM is an object-oriented representation of the web page, which can be modified with a scripting language such as JavaScript.

DOM level 0 was released in 1995. During 1997, intermediate DOM versions were released, which added support for DHTML (Dynamic HTML), where HTML is modified on user computer thru Javascript. However, these DOM versions were largely incompatible b/w IE and Netsscape. This led W3C tp release a standard known as DOM level 1. Then DOM level 2 was published in 2000, which introduced the getElementById function as well as an event model and support for XML namespaces and CSS. The latest DOM level 4 was released in 2015.

Layout engine of browsers parse HTML into DOM tree. The DOM represents the document as nodes and objects. These nodes are organized in a tree structure called the DOM tree, with the topmost node named as "Document object". Every element in a HTML document — the document as a whole, the head, tables within the document, table headers, text within the table cells—is part of the document object model for that document, so they can all be accessed and manipulated using the DOM and a scripting language like JavaScript. Initially DOM and Javascript were tightly interwined, but eventually, they evolved into separate entities. 

So, a typical DOM tree for HTML page would be something as shown on this wiki page (see top right pic): https://en.wikipedia.org/wiki/Document_Object_Model

DOM programming for HTML:

window and document objects:

The top most object in DOM is the window object which represents something like the browser tab, and the document object is the root of the HTML document itself (the HTML doc that you see in your browser currently). Each separate HTML doc in separate tab or window has it's own DOM tree, and they can't talk to each other.  There are many methods and properties associated with these objects (aka API)  that we can use to get access to various items in the HTML doc as well as modify them locally.

DOM tree: In DOM tree, top level "window" object has "document" object under it. Then this document object has <HTML> object which in turn has 2 objects: <HEAD> and <BODY> . <HEAD> object has <TITLE> object under it, while <BODY> object has various objects as <a>, <p>, <h1>, etc.

All items in the DOM are defined as nodes. There are many types of nodes, but there are three main ones that we work with most often:

  • Element nodes : In above DOM tree, all these objects as <HEAD>, <p> etc are elements, so they form element node.
  • Text nodes : Any text outside of any element is called text node. NOTE: text within element is not called a "text node", i.e text within <h1> tag is not a text node as it is inside "h1" element.
  • Comment nodes : Anything within comments is a comment node.

In addition to these three node types, the document tself is a document node, which is the root of all other nodes. window is a parent of document node. The DOM consists of a tree structure of nested nodes, which is often referred to as the DOM tree. Ultimately, everything in an HTML doc is present in this DOM tree. This DOM tree is what is used in javascript to manipulate html file that is loaded into the browser.

Properties: To access method or properties of an object, we do it as in other Object Oriented languages, which is object name followed by a dot and then the method/property name. So, to access the contents of body element, we can use "document.body", where document is the object and body is the property. This contains the whole <body> element, and so everything is printed out on console. Here Similarly we can change properties of an element via something like: document.body.style.backgroundColor = 'red';

We can follow the example given in digitalocean, by writing a file "index.html" and then opening it in firefox browser by entering this in address bar "file:///home/ashish/index.htmt" or whatever the path is to your file. Once the o/p is seen on the browser, you can go to "open menu" on top right side of firefox, click on "Web Developer" and then on "Web Console". This will bring a console (or something to type on with >>) in bottom of page. Now we can type any javascript commands on console (NOTE: all cmds below are javascript cmds):

>> window => this prints the "window" object. Window is the global, top-level object representing a tab in the browser. The window object has access to such information as the toolbar, height and width of the window, prompts, and alerts. The document object consists of what is inside of the inner window.

>> document => document object is the property of window object. this prints the document object. It shows the whole index.html file in HTMLDocument node which has 2 child nodes: <!DOCTYPE html> and <html>. There is also whole lots of other info displayed as properties, attributes, elements, etc. Name shown after the solid arrow on 1st line (that you expand by clicking on) shows the node name. Here, HTMLDocument is the node name of this node.

>> document.head => This refers to "head" property of object "document". head is an object as well as property of document object. This prints the head element and everything inside it. The head node shown on top of the tree has 3 child nodes: #text, <title> and #text. #text are blank for head node, as these refer to text outside of any element, before and after the title element. indentation b/w elements is counted as "text" node, even though this may not be visible. children for head is just one: <title> element

>> document.body => This refers to "body" property of object "document". body is an object as well as property of document object. This prints the body element and everything inside it. The body node has 3 child nodes: #text, <h1> and #text. #text are blank for body node. children for body is just one: <h1> element

>> document.documentElement => This refers to "html" property of object "document". html is an object as well as property of document object. This prints the html element and everything inside it. The html node has 3 child nodes: <head>, #text and <body>. #text is blank for html node. children for html are 2 nodes: <head> and <body> elements. There is no "document.html", instead "document.documentElement" used.

>> document.title => this prints the title element and everything inside it. This is the text inside title: "Learning the DOM". For some reason, "document.head.title" doesn't work as title is not a property of head.

>> document.h1 => this is undefined. Similarly document.body.h1 is undefined

>> document.body.nodeType => This gives the node type of <body> element which is an "element" type. "element" node type has value=1. We can also print nodeValue ( returns "null" as it has no text to return) or nodeName ( returns "body")

There are many more properties to traverse DOM tree, add/delete nodes, and modify the DOM itself. 

Methods: Above we called various properties for given objects. We can also call methods instead of properties. Few imp methods listed below:

0. console.log( ): This can be used to print anything out on console. This is useful during debug:

ex: >> console.log("Aamir"); => prints string "Aamir"

ex: >> console.log(var1); => This looks for a var named "var1" and if found, prints the valoe of that var.

These are the 5 ways to access HTML elements in the DOM — by ID, by class, by HTML tag name, and by selector (CSS selectors). 

1. getElementById( ): This gets all elements in document whose id match the given id.

ex: <a id="nav" href="/index.html">  Home </a>

>> document.getElementById('nav') => this returns the whole <a> element, i.e <a> .... </a>. We can put double quotes also around "nav" here, but since double quotes are used in html itself, we use single quotes here so that this code can work when it's embedded within html (else html parser will mistake double quotes inside here as ending double quotes for html and give erroneous results.

>> let navLink = document.getElementById('nav'); => here we assigned a var to store the <a> element. Just typing "navLink" on console, prints the entire <a> element

>> navLink.href = 'https://www.wikipedia.org'; => We can modify href attribute via this. On the webpage, we will see href change to this new value.

>> navLink.textContent = 'Navigate to Wikipedia'; => We can modify textContent property via this. On the webpage, we will see href change to this new value.

2. getElementsByClassName ( ): This returns an HTML collection of all elements in document whose class name match the given name. Since there may many elements matching the class name, this returns an array, so we need to use index number to access each individual entry of that array.

>> const demoClass = document.getElementsByClassName('demo'); => here demoClass is an array as there may be various instance with class = "demo"

>> demoClass[0].style.border = '1px solid orange'; => NOTE: this changes values for index 0 of demoClass var, implying changing value for the 1st occurence of class = demo.

3. getElementsByTagName( ): This returns an HTML collection of elements with the given tag name. This also returns an array, similar to getElementsByClassName ( ).

4. querySelector ( ): This returns single element for matching class, id, tag, etc in CSS selector format.

>> const demoClass = document.querySelector('.demo'); => This is same as 2 above, except that it returns only first matching element. NOTE the dot in .demo, which indicates class=demo

5. querySelectorAll ( ): This returns multiple elements for matching class, id, tag, etc in CSS selector format.

>> const demoClass = document.querySelectorAll('.demo'); => This is same as 2 above, it returns all matching elements. We can access all matching elements by using method forEach()
 

Traversing the DOM tree: We can traverse the tree by using these parent, child and sibling properties.

I. parent node: We can get parent of any node by using parentNode property of that object.

>>  let navLink = document.getElementById('nav') => gets the element <a> in var "navLink"

>> navLink.parentNode =>This returns the parent of <a> which is <body> node

>> navLink.parentNode.parentNode => this returns the parent of parent of <a> which is <html> node

II. children node: We can get children nodes of any node by using childNodes property of that object. There are many other properties also available. The array of child nodes or elements can be traversed by using "for ... of" loop.

>> navLink.childNodes =>This returns all the child nodes of <a> which is #text node (which is blank). Uusally it retrns an array or list as there are multiple child nodes.

III. sibling node: The siblings of a node are any node on the same tree level in the DOM. Siblings do not have to be the same type of node - text, element, and comment nodes can all be siblings. There are various sibling properties as previousSibling, nextSibling, etc.

Changing the DOM: Th whole purpose of javascript cmds is to modify the DOM tree. We can do this using various methods:

1. createElement ( ): Creates a new element node. Then we can add text to the element by using textContent property.

>> const paragraph = document.createElement('p'); => creates new element <p>, which creates <p></p>

>> paragraph.textContent = "I'm a brand new paragraph."; => this adds text to above element. So, paragraph var is now "<p>I'm a brand new paragraph.</p>

2. appendChild ( ): Adds a node as the last child of a parent element. insertBefore, replaceChild, removeChild are other methods available.

There are various other methods available to alter the DOM by modifying styles, classes, and other attributes of HTML element nodes. 

Events: Above methods change DOM by manually adding applying changes using the methods above. However, we have methods that get triggered on certain events, that are either initiated by the user or the browser itself. Then the webpage becomes responsive to user actions, which makes the page very interactive.

When a user clicks a button or presses a key, an event is fired. These are called a click event or a keypress event, respectively.

An event handler is a JavaScript function that runs when an event fires.

An event listener attaches a responsive interface to an element, which allows that particular element to wait and “listen” for the given event to fire.

There are three ways to assign events to elements:

  • Inline event handlers
  • Event handler properties
  • Event listeners

1. Inline event Handlers: These should not be used.

 2. addEventListerner(): It listens for an event, and performs an action when the event happens

ex: <button id="my_button">Change Background Color</button>

>>  let my_but = document.getElementById('my_button'); => this returns "button" element above, and assigns it to var "my_but"

>> my_but.addEventListener('click', () => { => This adds a event on this my_but button element, so that when it's clicked, the background color of all of body is changed to red.
>>   document.body.style.backgroundColor = 'red';
>> });

 -----------------------------------------------