Categories
JavaScript JavaScript Basics

Using HTML Audio and Video Elements

With HTML5, we are provided numerous tools and tags to work with multimedia. One of the new things that come with HTML5 is the ability to embed audio and video without needing plugins like Flash.

In this article, we’ll look at how to add audio and video elements to a web page and control it with JavaScript.

Adding Audio or Video Elements

To add audio and video elements, we use the audio and video tags respectively. They have a few attributes. They are:

  • autoplay — specifies whether the audio or video will play automatically
  • controls — specifies whether playback controls are shown
  • loop — specifies whether we want to play the clip again once it ends
  • muted — specifies if sound should play or not
  • preload — specifies which part of the clip should be preloaded. It can be auto , which loads everything, metadata, which loads only the metadata, or none, which loads nothing
  • src — the URL for the clip

To embed audio in our web pages, we can write the following:

<audio controls>  
  <source src="https://file-examples.com/wp-content/uploads/2017/11/file_example_OOG_1MG.ogg" type="audio/ogg">  
  <source src="https://file-examples.com/wp-content/uploads/2017/11/file_example_MP3_700KB.mp3" type="audio/mpeg">  
  Your browser does not support the audio tag.  
</audio>

In the code above, we specified the audio in different formats of the audio that we want to load.

Likewise, we can do the same with video:

<video controls width="250">  
  <source src="https://sample-videos.com/video123/mp4/240/big_buck_bunny_240p_30mb.mp4" type="video/mp4">  
  Your browser does not support the video tag.  
</video>

In both pieces of code, then text within the tag is the fallback text in case the browser doesn’t support these tags.

Controlling the Elements with JavaScript

We can customize the functionality of the audio or video element with JavaScript code. The following are methods are available for controlling the playback of audio or video elements:

  • play — start playing the audio or video
  • pause — pausing the audio or video
  • load — reload the audio or video element
  • addTextTrack — add a text track to audio or video
  • canPlayType — check if the browser can play the specified type of audio or video

There’re also some properties that we can set the control the audio or video playback:

  • currentTime — sets the current time of the audio or video in seconds
  • defaultMuted — indicate whether the audio output should be muted by default
  • defaultPlaybackRate — a number indicating the default playback for the media
  • loop — boolean indicating whether we want restart playback after it ends
  • muted — boolean we can set for muting the audio
  • playbackRate — sets the playback rate of the clip
  • volume — change the volume of the audio or video

We can use these methods and value properties as follows. First, we add our clip into our HTML code:

<video controls width="250">  
  <source src="https://sample-videos.com/video123/mp4/240/big_buck_bunny_240p_30mb.mp4" type="video/mp4">  
  Sorry, your browser doesn't support embedded videos.  
</video>

Then we can add buttons to change various things like the playback rate or muting the audio as follows. First, we add some buttons to let us click to change the settings:

<button id='fast-button'>1.5x speed</button>
<button id='fastest-button'>2x speed</button>
<button id='mute'>Toggle Mute  </button>

Then we add some code to get the button and video elements and set the settings accordingly.

const fastButton = document.querySelector('#fast-button');  
const fastestButton = document.querySelector('#fastest-button');  
const muteButton = document.querySelector('#mute');  
const video = document.querySelector('video');

fastButton.onclick = () => {  
  video.playbackRate = 1.5  
}

fastestButton.onclick = () => {  
  video.playbackRate = 2  
}

muteButton.onclick = () => {  
  video.muted = !video.muted;  
}

In the code above, we get the elements and then in the click event handlers for the buttons, we set the playbackRate and toggle the muted properties for the video.

We can do something similar with the methods. For example, we can add the following buttons:

<button id='play'>Play</button>
<button id='pause'>Pause</button>

Then we can add the following buttons click handlers to play and pause the clip programmatically:

playButton.onclick = () => {  
  video.play();  
}

pauseButton.onclick = () => {  
  video.pause();  
}

This is handy for creating custom video and audio players that don’t use the default browser style, along with the controls attribute for showing or hiding the controls.

Another example is making a seek bar for our clip. We can do that by adding a range slider as follows:

<input type="range" name="time" id='time' min='0'>

Then we can set the max attribute of the slider to the duration of our clip and add an onchange event handler as follows:

timeInput.max = video.duration  
timeInput.onchange = (e) => {  
  video.currentTime = e.target.value;  
}

The let us seek to anywhere from the start to the end of the video as we slide back and forth with the slider.

Events

Audio and video elements also have the following events fired, so we can handle them with event handlers we wish to:

  • canplay — the browser can play the media, but estimates that not enough data will be available to finish playback without stopping to buffer.
  • canplaythrough — browser estimates that playback finish without stopping for more buffering
  • complete — playback ends
  • durationchange — duration has been updated
  • emptied — media has become empty
  • ended — playback ended before the end of the clip was reached
  • loadeddata — the first frame has finished loading
  • loadedmetadata — metadata has been loaded
  • pause — playback is paused
  • play — playback began
  • playing — playback is ready to start after having been paused or delayed due to lack of data
  • progress — fired periodically as browser loads a resource
  • ratechange — playback rate changed
  • seeked —seek operation completed
  • seeking — seek operation began
  • stalled —a user-agent tries to fetch media data, but nothing is coming in
  • suspend — media data loading has been suspended
  • timeupdate — the time indicated by the currentTime attribute has been updated
  • volumechange — volume changed
  • waiting — playback stopped because of a temporary lack of data
Categories
JavaScript JavaScript Basics

Using Design Mode and execCommand to Fiddle with Web Pages

To make fiddling with the design of webpages easy, modern browsers have a design mode built-in. We can toggle it on with the document.designMode property set to 'on' .

Furthermore, we can send commands to change the page when it’s design mode with the document.execCommand method.

In this article, we’ll look at how to use the document.execCommand method to change web pages in design mode on the fly.

Usage

The document.execCommand method takes 3 arguments. The syntax is the following:

document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)

The parameters are:

  • aCommandName — a string specifying the name of the command to run.
  • aShowDefaultUI — a boolean indicating whether the default user interface should be shown. This isn’t supported in Mozilla
  • aValueArgument — a string that provides information for commands requires input. For example, a URL for an image is required for the insertImage command.

It returns false if a command is unsupported or disabled.

We can run the commands from the browser console or in our code. The changes will be cleared once we refresh.

Commands

The follows commands can be run with execCommand :

backColor

Changes the background color of the block that’s selected.

We can change the selected background to blue as follows:

document.execCommand('backColor', false, 'blue');

bold

Toggle selected text’s boldness on and off.

For example, we can use it as follows:

document.execCommand('bold')

ClearAuthenticationCache

Clears authentication credentials from the cache.

For instance, we can run:

document.execCommand("ClearAuthenticationCache","false");

to make sure that we have to authenticate again.

contentReadOnly

Marks content as read-only or editable. A boolean is required as the value argument. This isn’t supported by Internet Explorer.

We can use it like the following code:

document.execCommand('contentReadOnly', false, true)

copy

Copies the current selection to the clipboard. Support may vary between browsers.

For example, we can write:

document.execCommand('copy')

createLink

Create a link from the selection. A URI string is required in the value argument to set the link’s href attribute. The URI must at least have 1 character which may be whitespace. IE will also create a link with a null value.

We can use it as follows:

document.execCommand('createLink', true, 'http://www.google.com')

cut

Remove the selected text and copied it to the clipboard. Support may vary between browsers.

We can use it as follows:

document.execCommand('cut')

decreaseFontSize

Add a small tag around the select text. This command isn’t supported by IE.

For example, we can use it by writing:

document.execCommand('decreaseFontSize')

defaultParagraphSeparator

Change the paragraph separator used when new paragraphs are created in editable text regions.

We can use by writing:

document.execCommand('defaultParagraphSeparator', false, 'br')

to change the separator to br .

delete

Deletes the current selection. We can use it by writing:

document.execCommand('delete')

enableAbsolutePositionEditor

Toggle the grabber that allows absolutely positioned elements to be moved around. It’s disabled by default in Firefox 63 beta or dev editions.

We can use it by running:

document.execCommand('enableAbsolutePositionEditor', true, true)

fontName

Change the font name for the selection or at the insertion point.

For example, we can use it by writing:

document.execCommand('fontName', true, 'Arial')

foreColor

Change the font color for the selection or insertion point. A hexadecimal color value is required as the value argument.

For example, we can write:

document.execCommand('foreColor', true, '#4287f5')

formatBlock

Add an HTML block-level element around the line containing the current selection.

We can use it by writing:

document.execCommand('formatBlock', true, 'blockquote')

Where 'blockquote' can be replaced by other block-level elements.

forwardDelete

Deletes the character ahead of the cursor’s position. It’s the same as hitting the Delete key on a Windows keyboard.

For example, we can use it by running:

document.execCommand('forwardDelete')

heading

Add a heading element around the selection or insertion point line. Requires the tag name string as the value argument. This command isn’t supported by IE or Safari.

For example, we can use it as in the following code:

document.execCommand('heading', true, 'H1')

hiliteColor

Change the background color for the selection or at the insertion point. It requires a color value string as a value argument. It’s not supported by IE.

We can run:

document.execCommand('hilitecolor', true, 'red')

to change the highlight color to red.

increaseFontSize

Add a big tag around the selector or at the insertion point. It’s not supported by IE.

document.execCommand('increaseFontSize')

indent

Indent the line containing the selection or insertion point. The least indented line will be indented if there’re multiple lines at different levels of indentation.

We can run:

document.execCommand('indent')

to indent the text.

insertBrOnReturn

insertBrOnReturn adds a line break or <br> element. It’s not supported by IE.

We can run:

document.execCommand('insertBrOnReturn')

insertHorizontalRule

Insert an hr element at the insertion point or replace the selection with it.

We can run:

document.execCommand('insertHorizontalRule')

insertHTML

Insert an HTML string at the insertion point, which deletes the selection. It’s not supported by IE, and requires valid HTML string.

We can run it by typing in:

document.execCommand('insertHTML', false, '<b>foo</b>')

insertImage

Inserts an image at the insertion point. A URL for the string is required for the src attribute of the image.

For example, we can run:

document.execCommand('insertImage', false, 'https://images.unsplash.com/photo-1496096265110-f83ad7f96608?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80')

insertOrderedList

Inserts a numbered ordered list for the selection or at the insertion point.

We can use it as follows:

document.execCommand('insertOrderedList');

insertUnorderedList

Inserts a bulleted unordered list for the selection or at the insertion point.

We can use it as follows:

document.execCommand('insertUnorderedList');

insertParagraph

Add a paragraph around the selection or the current line. IE inserts a paragraph at the insertion point and deletes the selection.

We can use it as follows:

document.execCommand('insertParagraph');

insertText

Adds the given plain text at the insert point and deletes the selection.

We can use it as follows:

document.execCommand('insertText');

italic

Toggle italics on and off for the selection or at the insertion point. IE uses em instead of i .

document.execCommand('italic');

justifyCenter

Centers the selection or insertion point.

We can use it as follows:

document.execCommand('justifyCenter');

justifyFull

Justifies the selection or insertion point.

We can use it as follows:

document.execCommand('justifyFull');

justifyLeft

Left justifies the selection or insertion point.

We can use it as follows:

document.execCommand('justifyLeft');

justifyRight

Right justifies the selection or the insertion point.

We can use it as follows:

document.execCommand('justifyRight');

outdent

Outdents the line containing the selection or insertion point.

We can use it as follows:

document.execCommand('outdent');

paste

Paste the clipboard content at the insertion and replaces the current selection. It’s disabled for web content.

We can use it as follows:

document.execCommand('paste');

redo

Redo a previously undone command.

We can use it as follows:

document.execCommand('redo');

removeFormat

Removes all formatting from the current selection.

We can use it as follows:

document.execCommand('removeFormat');

selectAll

Selects all the content of the editable region.

We can use it as follows:

document.execCommand('selectAll');

strikeThrough

Toggle strikethrough on or off for the selection or insertion point.

We can use it as follows:

document.execCommand('strikeThrough');

subscript

Toggle subscript on or off for the selection or insertion point.

We can use it as follows:

document.execCommand('subscript');

superscript

Toggle superscript on or off for the selection or insertion point.

We can use it as follows:

document.execCommand('superscript');

underline

Toggle underline on or off for the selection or insertion point.

We can use it as follows:

document.execCommand('underline');

undo

Undo to the last run command.

We can use it as follows:

document.execCommand('undo');

unlink

Removes the a element from a selected hyperlink.

We can use it as follows:

document.execCommand('unlink');

styleWithCSS

Toggle on or off the use of HTML tags or CSS for the generated markup. true modifies/generates style attributes in markup, false generate presentational elements.

We can use it as follows:

document.execCommand('styleWithCSS', true, true);

The document.execCommand method is very useful for fiddling with web pages that have design mode on. We can make lots of changes to formatting by running various commands listed above.

It’s more convenient than inspecting the element and then changing it manually if we want to make lots of changes.

Categories
JavaScript

Useful Lodash Array Functions — Fill and Find

Lodash is a utility library that has lots of methods for manipulating objects. It has stuff that we use all the time and also things that we don’t use frequently or don’t think of using.

In this article, we’ll look at more useful Lodash array methods, including fill , findIndex , and findLastIndex .

fill

The fill method fills elements of an array with value from the start index inclusive but not including the end index.

It takes up to 4 arguments. The first argument is the array to fill in the items into. The second is the value to fill the array with.

The third is an optional argument for the start index to fill entries with. The default value is 0.

The last argument is an optional argument for the end index to fill it up to. The default value is the array ‘s length .

It returns a new array with the filled entries.

For example, we can use it as follows:

import * as _ from "lodash";
const result = _.fill(new Array(5), 1, 0, 2);  
console.log(result);

Then we get:

[  
  1,  
  1,  
  null,  
  null,  
  null  
]

and assigned to result. Entries that aren’t filled are null .

If the end is bigger than the array’s length , as in the following code:

import * as _ from "lodash";
const result = _.fill(new Array(5), 1, 0, 10);  
console.log(result);

Then we get all the arrays filled:

[  
  1,  
  1,  
  1,  
  1,  
  1  
]

and assigned to result. We can also fill items in the middle of an array as follows:

import * as _ from "lodash";
const result = _.fill(new Array(5), 1, 1, 2);  
console.log(result);

Then we get:

[  
  null,  
  1,  
  null,  
  null,  
  null  
]

and assigned to result.

findIndex

The findIndex method gets the first match of an object from an array that satisfies a given condition.

It takes up to 3 arguments. The first is the array to search for items with. The second is an optional argument where we pass in the callback function that returns the condition to look for. Finally, the third argument is an optional argument to specify where to start.

It returns the index of the entry if a match is found. Otherwise, it returns -1.

We can use it as follows:

import * as _ from "lodash";
const people = [  
  { name: "Joe", age: 10 },  
  { name: "Mary", age: 12 },  
  { name: "Jane", age: 13 }  
];  
const result = _.findIndex(people, p => p.age === 10);

Then we get 0 for result.

We can also pass in a starting index as follows:

import * as _ from "lodash";
const people = [  
  { name: "Joe", age: 10 },  
  { name: "Mary", age: 12 },  
  { name: "Jane", age: 13 }  
];  
const result = _.findIndex(people, p => p.age === 10, 1);

Then we get -1 since nothing from the index 1 and on has an entry with age 10.

findLastIndex

This is similar to findIndex but it finds the last match instead of the first match. The search is also done from end to start.

The arguments are the same as the same as findIndex , except that the third argument takes the end index which too starts the search from the index of the first index.

For example, we can use it as follows:

import * as _ from "lodash";
const people = [  
  { name: "Joe", age: 10 },  
  { name: "Mary", age: 12 },  
  { name: "Jane", age: 13 }  
];  
const result = _.findLastIndex(people, p => p.age === 12);

Then we get 1 for result since the entry match the condition is in the 2nd entry.

We can also pass in the end index as the third argument. For example, we can write:

import * as _ from "lodash";
const people = [  
  { name: "Joe", age: 10 },  
  { name: "Mary", age: 12 },  
  { name: "Jane", age: 13 }  
];  
const result = _.findLastIndex(people, p => p.age === 13, 1);

Then we get -1 since the search starts at index 1 and goes down to 0. Nothing in index 1 or less meets the condition, so we get -1.

The fill method fills elements of an array with value from the start index inclusive but not including the end index.

The findIndex method gets the first match of an object from an array that satisfies a given condition and returns the index of that entry.

findLastIndex is similar to findIndex but it finds the last match instead of the first match. The search is also done from the end index to the start.

Categories
JavaScript JavaScript Basics

Use the JavaScript Notification API to Display Native Popups

The Notifications API lets us display popups that show up as a native desktop or mobile notification. The functionality varies across platforms but they generally provide a way to asynchronously provide information to the user.

Create a New Notification

We can create a new notification with the Notification constructor. It takes 2 arguments. The first is the title, and the second is an object with a variety of properties and is optional:

  • dir: the direction of the displayed notification. Default value is auto, but it can also be rtl for right to left or ltr for left to right.
  • lang: string value for the language. Possible values are BCP 47 language tags.
  • badge: string which contains the URL for an image used to represent the notification when there isn’t enough space to display it.
  • body: a string with the text of the notification.
  • tag: a string with the identifying tag of the notification
  • icon: URL string with the icon’s URL
  • image: URL string for the image to be displayed.
  • data: data we want to be associated with the notification.
  • vibrate: vibration pattern for devices that vibrate.
  • renotify: boolean value specifying whether the user should be notified after a new notification replaces the old one. Default value is false.
  • requireInteraction: indicates whether the notification should remain active until the user clicks or dismisses it. Default value is false.
  • actions: an array of NotificationAction which have actions that are available to the user when the notification is displayed. It’s an object with a name, title, and icon properties.

We can define a simple notification as follows:

const options = {  
  body: "body",  
  icon:  
    "https://www.iconninja.com/files/926/373/306/link-chain-url-web-permalink-web-address-icon.png"  
};const n = new Notification("title", options);

To see the notification, we have to set Notification to always display in our browser.

We should see the text we set and the icon we specified in the icon property.

Methods of the Notification Object

Requesting Permission

We can request permission with the requestPermission static method. It returns a promise which resolves when the permission for showing the notification is allowed or denied.

It resolves with an object which has the permission data.

The browser will ask for permission to display notifications for the domain when we run this method.

For example, we can use it as follows:

(async () => {  
  try {  
    const permission = await Notification.requestPermission();  
    console.log(permission);  
    const options = {  
      body: "body",  
      icon:  
        "https://www.iconninja.com/files/926/373/306/link-chain-url-web-permalink-web-address-icon.png"  
    };  
    const n = new Notification("title", options);  
  } catch (error) {  
    console.log(error);  
  }  
})();

If permission is granted, the console.log in the try block will log granted. Otherwise, it will log denied from the console.log in the catch block.

Closing the Notification Programmatically

We can close a notification programmatically with the close method, which is an instance method of a Notification object.

For example, we can use it as follows:

(async () => {  
  try {  
    const permission = await Notification.requestPermission();  
    console.log(permission);  
    const options = {  
      body: "body",  
      icon:  
        "https://www.iconninja.com/files/926/373/306/link-chain-url-web-permalink-web-address-icon.png"  
    };  
    const n = new Notification("title", options);  
    await new Promise(resolve => {  
      setTimeout(() => {  
        n.close();  
        resolve();  
      }, 5000);  
    });  
  } catch (error) {  
    console.log(error);  
  }  
})();

In the example above, we called close inside the callback of the setTimeout method. This makes it close automatically after 5 seconds.

Event Handlers

Notification objects also have their own event handlers. They events are onclick, onclose, onerror, and onshow. We can assign our own event handler functions to them.

onclick

We can assign an event handler to the onclick property when we want to do something when the notification is clicked. For example, we can write:

(async () => {  
  try {  
    const permission = await Notification.requestPermission();  
    console.log(permission);  
    const options = {  
      body: "body",  
      icon:  
        "https://www.iconninja.com/files/926/373/306/link-chain-url-web-permalink-web-address-icon.png"  
    };  
    const n = new Notification("title", options);  
    n.onclick = () => {  
      alert("Notification clicked");  
    };  
  } catch (error) {  
    console.log(error);  
  }  
})();

This shows an alert in the browser tab when our notification is clicked. The event handler function can take one parameter, which is the event object.

The default behavior is to move focus to the viewport of the notification’s related browsing context. We can call preventDefault() on the event parameter that we pass in to prevent that as follows:

(async () => {  
  try {  
    const permission = await Notification.requestPermission();  
    console.log(permission);  
    const options = {  
      body: "body",  
      icon:  
        "https://www.iconninja.com/files/926/373/306/link-chain-url-web-permalink-web-address-icon.png"  
    };  
    const n = new Notification("title", options);  
    n.onclick = event => {  
      event.preventDefault();  
      alert("Notification clicked");  
    };  
  } catch (error) {  
    console.log(error);  
  }  
})();

We can make the notification do something when it’s closed by assigning an event handler function to the onclose property.

Likewise, we can do the same for the onerror property to handle errors and the onshow property to handle the show event, which is fired when the notification is displayed.

Conclusion

As we can see, the Notification API is a really simple way to display native notifications from the web apps we write. We ask for permission to display notifications with the static Notification.requestPermission method.

Once the promise is resolved when the user allows notifications to be displayed, then we just create a Notification object with the options we want. Then the notification will be displayed.

Categories
JavaScript JavaScript Basics

Useful DOM Traversal Methods

The main use of client-side JavaScript is to manipulate web pages dynamically. We can do this with the DOM traversal methods and properties available to DOM Node objects.

Adding or changing child and sibling elements is easy for any given Node since there are properties built into DOM Node objects to perform these actions. The following are methods of a DOM Node object for getting parent, child, and sibling nodes or elements.

appendChild

The appendChild methods let us attach a child node to a given HTML element as the last child node of the current node. If the argument referenced an existing node on the DOM tree then the node will be detached from its current position and attached to its new position.

It takes one argument, which is a DOM Node object.

For example, given 2 existing nodes in the following HTML:

<div id='foo'>  
  foo  
</div>  
<div id='bar'>  
  bar  
</div>

We can attach the element with ID bar as a child to the element with ID bar as follows:

const foo = document.querySelector('#foo');  
const bar = document.querySelector('#bar');
foo.appendChild(bar);

Once we ran that, we should get the following structure:

<div id="foo">  
  foo  
  <div id="bar">  
    bar  
  </div>  
</div>

We can also use it to create an element that’s created on the fly. For example, if we have the following HTML:

<div id='foo'>  
  foo  
</div>

Then we can write the following code to attach a new p element to the div with ID foo:

const foo = document.querySelector('#foo');  
const bar = document.createElement('p');  
bar.textContent = 'bar';
foo.appendChild(bar);

In the code above, we used createElement to create a new p element. Then we set the textContent property to add text inside the p element. At the end, we can appendChild on foo with bar as the argument to attach bar as the child of foo .

cloneNode

The cloneNode method clones a Node object and optionally, all of its content. It doesn’t clone all the content of the Node by default.

It takes one argument, which is an optional argument indicate if it’s a deep clone, which means everything will be cloned. true means do a deep clone and false otherwise.

For example, given the following HTML:

<div>  
  foo  
</div>

We can write the following JavaScript code to clone the div and then attach it to the body element as the last child:

const fooDiv = document.querySelector('div');  
const fooClone = fooDiv.cloneNode(true);  
document.body.appendChild(fooClone);

We pass in true to the cloneNode method to clone everything. Then we call appendChild on document.body with the cloned object passed in as the argument to add it as the child of body.

compareDocumentPosition

The compareDocumentPosition method compares the position of the given node against another node in any document. It takes a DOM Node object as its argument.

It returns a bitmask with the following possible values

  • DOCUMENT_POSITION_DISCONNECTED — 1
  • DOCUMENT_POSITION_PRECEDING — 2
  • DOCUMENT_POSITION_FOLLOWING — 4
  • DOCUMENT_POSITION_CONTAINS — 8
  • DOCUMENT_POSITION_CONTAINED_BY — 16
  • DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC — 32

For example, given the following HTML:

<div id='foo'>  
  foo  
</div>  
<div id='bar'>  
  bar  
</div>

We can write the following JavaScript to compare the position of the div with ID foo and the one with ID bar:

const foo = document.querySelector('#foo');  
const bar = document.querySelector('#bar');
const relativePos = foo.compareDocumentPosition(bar);  
console.log(relativePos);

The code above should get us 4 for relativePos, which means the element with ID bar follows the element with ID foo.

contains

The contains method checks if a DOM node is inside the given node. It takes one argument, which is a Node object that we want to check if it’s inside the one that this method is called on.

It returns true if the node in the argument is inside the one that’s called and false otherwise.

For example, given the following HTML:

<div id='foo'>  
  foo  
</div>  
<div id='bar'>  
  bar  
</div>

Then we can write the following JavaScript to check if the div with ID bar is inside the div with ID foo:

const foo = document.querySelector('#foo');  
const bar = document.querySelector('#bar');
const fooContainsBar = foo.contains(bar);  
console.log(fooContainsBar);

Of course, fooContainsBar should be false since the div with ID foo isn’t inside the div with ID bar.

On the other hand, if we have the following HTML instead:

<div id='foo'>  
  foo  
  <div id='bar'>  
    bar  
  </div>
</div>

Then with the same JavaScript code as the first example, fooContainsBar should true since div with ID foo is inside the div with ID bar.

getRootNode

The getRootNode method returns the Node object’s root, which optionally includes the shadow root if it’s available.

It takes an optional argument with an object with the following properties:

  • composed — a boolean that indicates rather the shadow root should be included. It defaults to false

It returns the Node that either returns an element that’s the root of the given Node or the shadow root will be returned for elements inside the shadow DOM.

For example, if we have the following HTML:

<div id='foo'>  
  foo  
</div>

Then we can call the getRootNode method as follows:

const foo = document.querySelector('#foo');const root = foo.getRootNode();  
console.log(root);

We should get the HTML document as the root node since it’s not inside a shadow DOM.

The root will be the shadow root for Web Components. For example, if we have the following web component:

customElements.define('custom-p',  
  class extends HTMLElement {  
    constructor() {  
      super(); const pElem = document.createElement('p');  
      pElem.id = 'p-element';  
      pElem.textContent = 'shadow p' 
      const shadowRoot = this.attachShadow({  
        mode: 'open'  
      });  
      shadowRoot.appendChild(pElem);  
    }  
  }  
);

And we have the Web Component added in the HTML code:

<custom-p></custom-p>

Then we can get the root node of the element with the ID p-element by writing:

const pElement = document.querySelector('custom-p').shadowRoot.querySelector('#p-element');  
const rootNode = pElement.getRootNode();  
console.log(rootNode);

First, we get the custom element, then we get the shadowRoot property which lets us access the shadow DOM of our custom-p web component. Then we can get the p element with the ID p-element with the shadow root.

After that, we get the root node of it by callinggetRootNode on pElement which represents p element with the ID p-element .

The console.log should get us the shadow root of the Web Component.

Conclusion

With these DOM traversal methods, we can set the nodes however we like for simple situations. Also, there’re methods to check whether an element is the child of another one, and also to get the root node of the given element.