When we created popovers in the previous few lessons, we had to make them manually and add them into the HTML. This method is great for creating custom popovers.
But if you need a generic popover that contains one paragraph of text, you can create the popover programmatically.
Preparations
Let’s start by deleting the bottom popover. We’ll create it with JavaScript.
<!-- Delete this --><div id="pop-4" class="popover" data-position="bottom"> <p>The quick brown fox jumps over the lazy dog.</p></div>Making a popover with JavaScript
Let’s create a function called createPopover to make a popover.
function createPopover() { // ...}Each popover is a <div> element. We can create the <div> with createElement.
function createPopover() { const popover = document.createElement('div')}Each popover has the popover class. We can add the class with classList.add.
function createPopover() { const popover = document.createElement('div') popover.classList.add('popover')}We need to know which position to display the popover (top, right, bottom, or left). We can get the direction from the trigger.
function createPopover(popoverTrigger) { // ... popover.dataset.position = popoverTrigger.dataset.popoverPosition}We also need to set the popover’s id to the same value as the trigger’s data-target attribute.
function createPopover(popoverTrigger) { // ... popover.id = popoverTrigger.dataset.target}Finally, the popover needs content. We can send content from the trigger to the popover through another custom attribute. Let’s call it data-content.
<button id="pop-4" class="popover-trigger" data-popover-position="bottom" data-content="Hello world!"> <svg viewBox="0 0 40 20"> <use xlink:href="#arrow"></use> </svg></button>function createPopover(popoverTrigger) { // ...
const p = document.createElement('p') p.textContent = popoverTrigger.dataset.content
popover.appendChild(p)}You should see the correct Popover’s HTML if you log it into the console. (You’ll have to comment out the forEach code to log this).
function createPopover(popoverTrigger) { // ... console.log(popover)}
const bottomPopoverTrigger = document.querySelector( '.popover-trigger[data-popover-position="bottom"]',)const popover = createPopover(bottomPopoverTrigger)
The popover will always be placed as a direct descendant of the <bod> element. Since that’s the case, we can append the popover to the DOM inside createPopover.
function createPopover(popoverTrigger) { // ... document.body.appendChild(popover)}
Positioning the created popover
We assumed all popovers are in the DOM in the forEach code.
popoverTriggers.forEach(popoverTrigger => { // This assumes the popover is in the DOM const popover = document.querySelector(`#${popoverTrigger.dataset.target}`)
// ...})But we know that assumption is invalid now. We need to create popovers when we can’t find them in the DOM.
popoverTriggers.forEach(popoverTrigger => { let popover = document.querySelector(`#${popoverTrigger.dataset.target}`)
if (!popover) { createPopover(popoverTrigger) } // ...})Next, we need to get the created popover from the DOM to use it in calculatePopoverPosition. We can get the popover if we return the popover from createPopover.
function createPopover(popoverTrigger) { // ... return popover}popoverTriggers.forEach(popoverTrigger => { // ... if (!popover) { popover = createPopover(popoverTrigger) } // ...})Now the popover should work as before.
A small cleanup
Here are the first few lines of code we wrote in the forEach block.
popoverTriggers.forEach(popoverTrigger => { let popover = document.querySelector(`#${popoverTrigger.dataset.target}`)
if (!popover) { popover = createPopover(popoverTrigger) } // ...})We’re trying to do two things here:
- Find the popover from the DOM
- If it fails, create a popover
We can simplify these two statements with an OR operator.
popoverTriggers.forEach(popoverTrigger => { const popover = document.querySelector(`#${popoverTrigger.dataset.target}`) || createPopover(popoverTrigger) // ...})The document.querySelector part is really hard to read. We can put it into a function called getPopover to simplify things.
function getPopover(popoverTrigger) { return document.querySelector(`#${popoverTrigger.dataset.target}`)}Using it:
popoverTriggers.forEach(popoverTrigger => { const popover = getPopover(popoverTrigger) || createPopover(popoverTrigger) // ...})That’s it!
Welcome! Unfortunately, you don’t have access to this lesson. To get access, please purchase the course or enroll in Magical Dev School.
Unlock this lesson