mirror of
https://github.com/bendtherules/UiQuestions.git
synced 2026-08-18 22:02:42 +00:00
248 lines
7.7 KiB
Plaintext
248 lines
7.7 KiB
Plaintext
---
|
|
id: create-modify-element
|
|
# sidebar_label: DOM Manipulation
|
|
title: DOM Manipulation
|
|
slug: /
|
|
---
|
|
|
|
import Admonition from "../components/Admonition"
|
|
import Accordion from "../components/Accordion"
|
|
import InternalLink from "../components/InternalLink"
|
|
import MDN from "../components/MDNBadge"
|
|
|
|
:::note DOM interfaces
|
|
Every kind of **DOM** node is represented by an interface based on **Node** interface.
|
|
**Element, Document and DocumentFragment** interfaces inherit from Node. More about DOM interfaces [here](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model)
|
|
:::
|
|
|
|
## Finding elements
|
|
|
|
### 1. querySelector()
|
|
|
|
`document.querySelector(selector) : Element | null`
|
|
|
|
This method returns the **first element that matches the CSS selector**. If no match is found, it returns `null`.
|
|
|
|
```js
|
|
// <div className="box" />
|
|
document.querySelector(".box"); // returns .box
|
|
document.querySelector(".not-found"); // null
|
|
```
|
|
|
|
<Accordion>
|
|
<Admonition type="note" title="Also available on Element and fragment" id="link-element-has-qs">
|
|
Besides <b>Document</b>, this method is also available on <b>Element</b> and <b>DocumentFragment</b>.<br/>
|
|
If you want to look within a specific element, just use <code>ele.querySelector()</code> on the parent element.<br/>
|
|
If you want to look within a specific fragment, just use <code>df.querySelector()</code> on the parent fragment.
|
|
|
|
```js
|
|
// Example - outer is a parent element/fragment.
|
|
let innerEle = outer.querySelector(".inner");
|
|
```
|
|
</Admonition>
|
|
</Accordion>
|
|
|
|
<MDN title="querySelector" url="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector" />
|
|
|
|
### 2. querySelectorAll()
|
|
|
|
`document.querySelectorAll(selector) : NodeList`
|
|
|
|
This method returns **all the elements that match** the specified CSS selector.
|
|
|
|
It returns a **static NodeList**, which contains the matching elements. If no match is found, it returns empty NodeList.
|
|
|
|
:::note How to consume NodeList?
|
|
NodeList is a iterable, so it can be iterated using `for..of` loop, or converted to a array using spread syntax like `[...nodelist]`.
|
|
|
|
Here, the NodeList is static - meaning any changes in the DOM later does not affect the content of the existing collection. More about NodeList [here](https://developer.mozilla.org/en-US/docs/Web/API/NodeList).
|
|
:::
|
|
|
|
```js
|
|
let paras = document.querySelectorAll("p");
|
|
|
|
for (let p of paras) {
|
|
p.className = "note";
|
|
}
|
|
```
|
|
|
|
`querySelectorAll` is also available on <b>Element</b> and <b>DocumentFragment</b>, in the <InternalLink href="#link-element-has-qs">same way as querySelector</InternalLink>.
|
|
|
|
<MDN title="querySelectorAll" url="https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll" />
|
|
|
|
## Create / insert element
|
|
|
|
### 3. createElement()
|
|
|
|
`document.createElement(tagName) : Element`
|
|
|
|
This method creates a new HTML element, taking the specified HTML tag name as argument.
|
|
|
|
```js
|
|
document.createElement("div")
|
|
// creates a <div> element
|
|
```
|
|
|
|
<Accordion title="Related">
|
|
<Admonition type="note" title="Creating text node">
|
|
To add some text inside a element, you'll need to create a <b>text node</b>.
|
|
`createTextNode` method takes a string as input and returns a new TextNode.
|
|
|
|
```js
|
|
let ele = document.createElement("div")
|
|
let newText = document.createTextNode("Hello world")
|
|
|
|
ele.appendChild(newText)
|
|
// <div>Hello world</div>
|
|
```
|
|
</Admonition>
|
|
</Accordion>
|
|
|
|
<MDN title="createElement" url="https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement" />
|
|
|
|
### 4. setAttribute()
|
|
|
|
`Element.setAttribute(name, value)`
|
|
|
|
This method sets an attribute on the current element.
|
|
|
|
`name` - name of the attribute to add. Ex- "type".
|
|
`value` - value of the attribute. Ex- "text".
|
|
|
|
```js
|
|
let ele = document.createElement("input")
|
|
|
|
ele.setAttribute("type", "text")
|
|
// <input type="text"/>
|
|
```
|
|
<MDN title="setAttribute" url="https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute" />
|
|
|
|
|
|
### 5. appendChild()
|
|
|
|
`Node.appendChild(newNode)`
|
|
|
|
This method inserts a new node as the last child of the parent node.
|
|
|
|
```js
|
|
let eleDiv = document.createElement("div")
|
|
let eleH1 = document.createElement("h1")
|
|
|
|
eleDiv.appendChild(eleH1)
|
|
// <div><h1></h1></div>
|
|
```
|
|
|
|
<Accordion title="Edge cases and alternative">
|
|
<Admonition type="note" title="If it already has a parent">
|
|
If newNode is already a child of another node,
|
|
then it is removed from its existing parent and then added to the new parent.
|
|
</Admonition>
|
|
|
|
<Admonition type="note" title="If it is DocumentFragment" id="link-appendChild-documentFragment">
|
|
If newNode is a DocumentFragment, then - instead of adding the fragment itself as a child,
|
|
the entire content of the fragment is added as children of the parent node.
|
|
</Admonition>
|
|
|
|
<Admonition type="note" title=".append()">
|
|
There is a newer api called .append(), which is a superset of .appendChild().<br/><br/>
|
|
|
|
⭐️ .append() allows you to insert multiple child elements in a single call. It also allows string as input, which gets converted to Text node.
|
|
|
|
```js
|
|
ele1.append(ele2, ele3, 'hello world')
|
|
```
|
|
|
|
💔 .appendChild() only allows inserting a single element at a time.
|
|
</Admonition>
|
|
</Accordion>
|
|
|
|
<MDN title="appendChild" url="https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild" />
|
|
|
|
### 6. removeChild()
|
|
|
|
`Node.removeChild(childNode)`
|
|
|
|
This method tries to remove a child node from the parent and returns the removed node.
|
|
|
|
If the node to be removed is not a child of the parent node, it throws a `NotFoundError` DOMException.
|
|
|
|
```js
|
|
// <div class="parent">
|
|
// <div class="child"/>
|
|
// </div>
|
|
|
|
parentEle.removeChild(childEle)
|
|
```
|
|
|
|
<MDN title="removeChild" url="https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild" />
|
|
|
|
### 7. insertBefore()
|
|
|
|
`Node.insertBefore(newEle, refEle)`
|
|
|
|
This method inserts a new child node before another node within a parent.
|
|
|
|
It also works with **DocumentFragment**, by inserting all of its content in that position.
|
|
|
|
`newEle` - The node to be inserted.
|
|
|
|
`refEle` - The reference node before which newEle should be inserted. If refEle is `null`, then newEle is added as the last child.
|
|
|
|
```js
|
|
// <ul>
|
|
// <li> Apple </li>
|
|
// <li> Zebra </li>
|
|
// </ul>
|
|
|
|
// To add a new <li> above "Zebra"
|
|
|
|
let parent = document.querySelector("ul")
|
|
let ref = document.querySelector("li:last-child")
|
|
|
|
let newEle = document.createElement("li")
|
|
|
|
parent.insertBefore(newEle, ref)
|
|
```
|
|
|
|
:::note insertAfter()
|
|
There is no `insertAfter()` method. It can be emulated by combining insertBefore method with ele.nextSibling.
|
|
|
|
```js
|
|
parent.insertBefore(newEle, ref.nextSibling)
|
|
```
|
|
:::
|
|
|
|
<MDN title="insertBefore" url="https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore" />
|
|
|
|
### 8. Document Fragment
|
|
|
|
`document.createDocumentFragment() : DocumentFragment`
|
|
|
|
This method is used to create a new empty document fragment.
|
|
|
|
DocumentFragment can be considered to be a off-screen lightweight `document` object.
|
|
It is generally used for batching multiple operations - by doing them in the fragment over time and then rendering the whole content to the visible DOM in one shot .
|
|
|
|
Because fragment is not rendered, making changes to it doesn't cause any performance impact (no reflow). To **actually "render" the fragment** in the visible document, <Link title = "use appendChild" hash = "link-appendChild-documentFragment"/> or `insertBefore`.
|
|
|
|
```js
|
|
let fragment = document.createDocumentFragment()
|
|
|
|
// Insert / modify elements in fragment
|
|
|
|
// in dom, <div class="outer"/>
|
|
let outerEle = document.querySelector(".outer")
|
|
|
|
outerEle.appendChild(fragment)
|
|
// This will remove all content from fragment and
|
|
// insert them within outerEle.
|
|
|
|
```
|
|
|
|
<MDN title="Document Fragment" url="https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment" />
|
|
|
|
|
|
--------
|
|
|
|
In the next section, we'll see how to read information from a DOM element.
|