Cheat Sheet for JS methods to work with DOM, part 2
Mixin ParentNode
This mixing is designed to handle parent elements (ancestors), i.e. Elements containing one and more descendant (child elements).
children
— descendants of the element
const { children } = list // list.children
log(children)
/*
HTMLCollection(3)
0: li#item1.item
1: li#item2.item
2: li#item3.item
length: 3
*/
Such a structure is called the HTML collection and is an arms-like object (pseudoarray). There is another similar structure — list of Nodes(NodeList
).
Array-like objects have the length
property with the number of descendants, the forEach()
method, (NodeList
), which allows you to move the nodes (to make iteration). Such objects allow to obtain elements by index, by name (HTMLCollection
), etc. However, they have no methods of real arrays, such as map()
, filter()
, reduce()
etc., which makes work with them not very comfortable. Therefore, array objects are recommended to convert to arrays using the Array.from()
or Spread operator method:
const children = Array.from(list.children)
// or
const children = [...list.children]
log(children)
// [li#item1.item, li#item2.item, li#item3.item] - Normal array
firstElementChild
— first descendant — elementlastElementChild
— the last descendant — element
log(list.firstElementChild) // li#item1.item
log(list.lastElementChild) // li#item2.item
For further manipulations, we will need to periodically create new elements, so we will create another utility:
const createEl = (id, text, tag = 'li', _class = 'item') => {
const el = document.createElement(tag)
el.id = id
el.className = _class
el.textContent = text
return el
}
Our utility accepts 4 arguments: identifier, text, tag name and CSS class. 2 arguments (tag and class) have default values. The function returns an element ready for operation. Subsequently, we implement a more universal version of this utility.
prepend(newNode)
— adds an item to the top of the listappend(newNode)
— adds an element to the end of the list
// Create a new element
const newItem = createEl('item0', 0)
// and add it to the top of the list
list.prepend(newItem)// Create another item
const newItem2 = createEl('item4', 4)
// and add it to the end of the list
list.append(newItem2)log(children)
/*
HTMLCollection(5)
0: li#item0.item
1: li#item1.item
2: li#item2.item
3: li#item3.item
4: li#item4.item
*/
One of the interesting features HTMLCollection
is that it is “alive”, i.e. The elements returned by reference and their number are updated automatically. However, this feature cannot be used, for example, to automatically add event handlers.
replaceChildren(nodes)
— replaces descendants with new elements
const newItems = [newItem, newItem2]
// replace descendants with new elements
list.replaceChildren(...newItems) // list.replaceChildren(newItem, newItem2)log(children) // 2
The most versatile methods for obtaining references to elements are querySelector(selector)
and querySelectorAll(selector)
methods. Moreover, unlike getElementById()
, they can be called on any parent element, and not just on document
. Any valid CSS selector is transmitted as an argument to these methods. (id
, class
, tag
, etc):
// get an element `li` with `id === item0`
const itemWithId0 = list.querySelector('#item0')
log(itemWithId0) // li#item0.item// get all elements `li` with `class === item`
const allItems = list.querySelectorAll('.item')
log(allItems) // array-like object
/*
NodeList(2)
0: li#item0.item
1: li#item4.item
length: 2
*/
Create a universal utility to receive items:
const getEl = (selector, parent = document, single = true) => single ? parent.querySelector(selector) : [...parent.querySelectorAll(selector)]
Our utility takes 3 arguments: CSS selector, parent element and indicator of the number of elements (one or all). 2 arguments (ancestor and indicator) have default values. The function returns either one or all items (as a conventional array), which coincide with the selector, depending on the indicator value:
const itemWithId0 = getEl('#item0', list)
log(itemWithId0) // li#item0.itemconst allItems = getEl('.item', list, false)
log(allItems) // [li#item0.item, li#item4.item]
Mixin NonDocumentTypeChildNode
This mixing is designed to process subsidiaries that are not a document, i.e. all nodes except document
.
previousElementSibling
— previous elementnextElementSibling
—next element
log(itemWithId0.previousElementSibling) // null
log(itemWithId0.nextElementSibling) // #item4
Mixin ChildNode
This mixing is designed to process subsidiaries, i.e. elements that are descendants of other elements.
before(newNode)
— inserts a new element before the currentafter(newNode)
— inserts a new element after the current
// get `li` with `id === item4`
const itemWithId4 = getEl('#item4', list)
// create new element
const newItem3 = createEl('item3', 3)
// and insert it before `itemWithId4`
itemWithId4.before(newItem3)// create another one
const newItem4 = createEl('item2', 2)
// and insert it after `itemWithId0`
itemWithId0.after(newItem4)
replaceWith(newNode)
—replaces the current element of the new
// создаем новый элемент
const newItem5 = createEl('item1', 1)
// и заменяем им `itemWithId0`
itemWithId0.replaceWith(newItem5)
remove()
— removes the current element
itemWithId4.remove()
Node Interface
This interface is designed to process nodes.
nodeType
— type of node
log(list.nodeType) // 1// other options
/*
1 -> ELEMENT_NODE (element)
3 -> TEXT_NODE (text)
8 -> COMMENT_NODE (comment)
9 -> DOCUMENT_NODE (document)
10 -> DOCUMENT_TYPE_NODE (doctype)
11 -> DOCUMENT_FRAGMENT_NODE (fragment) etc.
*/
nodeName
— name of node
log(list.nodeName) // UL// other options
/*
- qualified name of the HTML element with capital (capital) letters
- qualified attribute name
- #text
- #comment
- #document
- doctype
- #document-fragment
*/
baseURI
— main path
log(list.baseURI) // .../dom/index.html
parentNode
— parent nodeparentElement
—parent element
const itemWithId1 = getEl('#item1', list)log(itemWithId1.parentNode) // #list
log(itemWithId1.parentElement) // #list
hasChildNodes()
— returnstrue
, If the element has at least one descendantchildNodes
— child nodes
log(list.hasChildNodes()) // true
log(list.childNodes)
/*
NodeList(3)
0: li#item1.item
1: li#item2.item
2: li#item3.item
*/
firstChild
— the first node-childlastChild
—the last node-child
log(list.firstChild) // #item1
log(list.lastChild) // #item3
nextSibling
— next nodepreviousSibling
— previous node
log(itemWithId1.nextSibling) // #item2
log(itemWithId1.previousSibling) // null
textContent
— getter / setter for extract / recording text
// get text
log(itemWithId1.textContent) // 1
// edit text
itemWithId1.textContent = 'item1'
log(itemWithId1.textContent) // item1// get text content from all children
log(list.textContent) // item123
To extract / write text there is another (outdated) getter / setter— innerText
.
cloneNode(deep)
— copies the node. Accepts a logical value determining the nature of copying: superficial — only the node itself is copied, the assembly itself and all its descendants is copied
// create a new list by copying the existing
const newList = list.cloneNode(false)
// remove the `ID` in the avoidance of collisions
newList.removeAttribute('id')
// change its text content
newList.textContent = 'new list'
// and insert it after an existing list
list.after(newList)// create another list
const newList2 = newList.cloneNode(true)
newList.after(newList2)
isEqualNode(node)
— compares nodesisSameNode(node)
— determines the identity of the nodes
log(newList.isEqualNode(newList2)) // true
log(newList.isSameNode(newList2)) // false
contains(node)
— returnstrue
, if the element contains the specified node
log(list.contains(itemWithId1)) // true
insertBefore(newNode, existingNode)
— adds a new node(newNode
) before existing (existingNode
)
// create new element
const itemWithIdA = createEl('#item_a', 'a')
// and insert it before `itemWithId1`
list.insertBefore(itemWithIdA, itemWithId1)
appendChild(node)
— adds a node to the end of the list
// создаем новый элемент
const itemWithIdC = createEl('#item_c', 'c')
// и добавляем его в конец списка
list.appendChild(itemWithIdC)
replaceChild(newNode, existingNode)
— replaces an existing node (existingNode
) with a new(newNode
):
// создаем новый элемент
const itemWithIdB = createEl('item_b', 'b')
// и заменяем им `itemWithId1`
list.replaceChild(itemWithIdB, itemWithId1)
removeChild(node)
— removes the specified child node
// получаем `li` с `id === item2`
const itemWithId2 = getEl('#item2', list)
// и удаляем его
list.removeChild(itemWithId2)
Document interface
This interface is designed to process theDocument
object.
URL
anddocumentURI
— document address
log(document.URL) // .../dom/index.html
log(document.documentURI) // ^
documentElement
:
log(document.documentElement) // html
getElementsByTagName(tag)
— returns all elements with the specified tag
const itemsByTagName = document.getElementsByTagName('li')
log(itemsByTagName)
/*
HTMLCollection(4)
0: li##item_a.item
1: li#item_b.item
2: li#item3.item
3: li##item_c.item
*/
getElementsByClassName(className)
— returns all items with the specified CSS class
const itemsByClassName = list.getElementsByClassName('item')
log(itemsByClassName) // ^
createDocumentFragment()
— returns a fragment of the document:
// create a fragment
const fragment = document.createDocumentFragment()
// create a new element
const itemWithIdD = createEl('item_d', 'd')
// add element to fragment
fragment.append(itemWithIdD)
// add fragment to list
list.append(fragment)
Fragments allow you to avoid creating unnecessary elements. They are often used when working with markup, hidden from the user using thetemplate
tag (method cloneNode()
returns DocumentFragment
).
createTextNode(data)
—create textcreateComment(data)
— create commentimportNode(existingNode, deep)
— creates a new node based on existing
// Creates a new list based on existing
const newList3 = document.importNode(list, true)
// insert it before the existing list
list.before(newList3)
// and remove to avoid conflicts
newList3.remove()
createAttribute(attr)
— creates the specified attribute
NodeIterator
and TreeWalker interfaces
NodeIterator
and TreeWalker
interfaces are designed to bypass (traverse) node trees. I did not come across the examples of their practical use, so I will limit the pair of examples:
// createNodeIterator(root, referenceNode, pointerBeforeReferenceNode, whatToShow, filter)
const iterator = document.createNodeIterator(list)
log(iterator)
log(iterator.nextNode()) // #list
log(iterator.nextNode()) // #item_a
log(iterator.previousNode()) // #item_a
log(iterator.previousNode()) // #list
log(iterator.previousNode()) // null// createTreeWalker(root, whatToShow, filter)
// apply filters - https://dom.spec.whatwg.org/#interface-nodefilter
const walker = document.createTreeWalker(list, '0x1', { acceptNode: () => 1 })
log(walker)
log(walker.parentNode()) // null
log(walker.firstChild()) // #item_a
log(walker.lastChild()) // null
log(walker.previousSibling()) // null
log(walker.nextSibling()) // #item_b
log(walker.nextNode()) // #item3
log(walker.previousNode()) // #item_b
Element interface
This interface is intended for processing elements.
localName
andtagName
— a tag name
log(list.localName) // ul
log(list.tagName) // UL
id
— getter / setter for IdentifierclassName
— getter / setter for CSS-class
log(list.id) // list
list.id = 'LIST'
log(LIST.className) // list
classList
— all CSS-classes of element(DOMTokenList
object)
const button = createEl('button', 'Click me', 'my_button', 'btn btn-primary')
log(button.classList)
/*
DOMTokenList(2)
0: "btn"
1: "btn-primary"
length: 2
value: "btn btn-primary"
*/