Introducing the Vue 3 personalized directive

I have developed a custom tooltip directive that is functioning correctly when using the beforeUpdate hooks, but not working with update hooks. The issue arises when multiple elements are created upon hovering over the h1 element, which triggers mouseover and mouseleave events.

Is there a way to prevent the creation of multiple elements in this scenario?

Being a beginner in custom directives, I would greatly appreciate any help or guidance you can provide.

<div class="tooltip"><h1>Hello world from html</h1></div>
<div class="tooltip"><h1>Hello world from html</h1></div>
<div class="tooltip"><h1>Hello world from html</h1></div>
<div class="tooltip"><h1>Hello world from html</h1></div>

tooltip.ts

const updateTooltip = (el: HTMLElement, value: DirectiveBinding["value"], modifiers: DirectiveBinding["modifiers"], arg: DirectiveBinding["arg"], vnode: VNode): void => {
if (!value.text) {
    el.classList.remove("tooltip-parent")
  }

  if (value.text) {
    tooltipDiv.classList.add("tooltip")
    tooltipDiv.innerHTML = value.text
    el.appendChild(tooltipDiv)
  }

  if (value.displayArrow) {
    el.style.setProperty(Tooltip.arrowDisplay, "inline")
    argTooltip?.style.setProperty(Tooltip.arrowDisplay, "inline")
  }

  tooltipPlacement(value, el, argTooltip, argTooltipDiv)

}

export const tooltip = {
  mounted: (el: HTMLElement, { value, modifiers, arg }: DirectiveBinding): void => {
    if (typeof value === "object" && value.text) {
      el.classList.add("tooltip-parent")
    }

    if (typeof value === "string" && value) {
      el.classList.add("tooltip-parent")
    }

    updateTooltip(el, value, modifiers, arg)
  },

  beforeUpdate: (el: HTMLElement, { value, modifiers, arg }: DirectiveBinding): void => {
    updateTooltip(el, value, modifiers, arg)
  },
}

tooltipPlacement.ts

export const tooltipPlacement = (value: DirectiveBinding["value"], el: HTMLElement, argTooltip: HTMLElement, argTooltipDiv: HTMLDivElement) => {
 if (value.theme) {
     for (const [key, val] of Object.entries(value.theme) as [string, any][]) {
       switch (key) {
            case "hide":
            watch(
              () => val,
              () => {
                if (val) {
                  argTooltip?.style.setProperty(Tooltip.opacity, "0")
                  argTooltip?.style.setProperty(Tooltip.visibility, "hidden")
                  /****  arrow ****/
                  argTooltip?.style.setProperty(Tooltip.arrowOpacity, "0")
                  argTooltip?.style.setProperty(Tooltip.arrowVisibility, "hidden")
                }

                if (!val) {
                  console.log("show")
                  argTooltip?.style.setProperty(Tooltip.opacity, "1")
                  argTooltip?.style.setProperty(Tooltip.visibility, "visible")
                  /****  arrow ****/
                  argTooltip?.style.setProperty(Tooltip.arrowOpacity, "1")
                  argTooltip?.style.setProperty(Tooltip.arrowVisibility, "visible")
                }
              },
              { immediate: true },
            )
            break
          default:
            break
      }
    }
  }
}

Template

<template>
  <div>
    <div class="p-6 centered flex-col space-y-6">
      {{ !!hideTooltip }}
      <h1>Tooltip</h1>
      <br />
      <p v-tooltip:actions.arrow="tooltipContent(html, tooltipTheme, true)" class="border w-40 h-20 text-center">hello world</p>
    </div>
    <div class="p-6 centered flex-col space-y-6">
      <h1 class="h-20" @mouseover="hideTooltip = false" @mouseleave="hideTooltip = true">Actions</h1>
      <br />
      <p class="h-60 border px-4 actions">Test of args tooltip</p>
      <button class="mt-10 p-6" @click="hideTooltip = !hideTooltip">{{ hideTooltip ? "Show Tooltip" : "Hide" }}</button>
    </div>
  </div>
</template>

Script

<script lang="ts" setup>
import { tooltipContent, ThemeOptions } from "../directives/tooltip"
import { ref, computed } from "vue"

const hideTooltip = ref(true)

const html = ref("<h1>Hello world from html</h1>")

const tooltipTheme = computed((): ThemeOptions => {
  return {
    placement: "leftTop",
    argTxt: html.value,
    hide: !!hideTooltip.value,
    maxWidth: "300px",
  }
})
</script>

Answer №1

After implementing this code snippet, the problem was resolved:

let tooltipElement = el.querySelector(".tooltip") as HTMLDivElement;

   if (!tooltipElement) {
      tooltipDiv.classList.add("tooltip");
      tooltipDiv.innerHTML = value;
      el.appendChild(tooltipDiv);
    }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Modifying HTML files in a Node.js environment with the fs module

Struggling with learning node.js and back-end development, I encountered a problem that I can't solve. Can anyone lend a hand? I've been working on changing my HTML page from h1.html to h2.html, but I keep encountering the following error: (Error ...

Sending a component as a prop to another component

I want to pass a component with props as a prop to another component. Here is an example of what I am trying to achieve: const App = ({ routes, graphqlProvider, themeProvider }) => { const GraphqlProvider = graphqlProvider const ThemeProvider = the ...

The Challenge of Using the "this" Keyword in ReactJS Functional Components

I couldn't find any answers to my specific question. I want to know how to convert the "this" keyword into a React functional component in the following situation: <SimpleStorage parent={this}/>. This component is part of a library (called react ...

Javascript solution to initiate automatic download

Is there a method to automatically download a file upon receiving the AJAX response from a Post request? I am unable to utilize window.open() as I do not possess a valid URL. Could Javascript or the Dojo toolkit be used to trigger the download of the fil ...

Incorporate real-time calculations using JavaScript (jQuery) with variables including initialization in HTML code

As a newcomer to JavaScript, I am encountering an issue that I need help with: I would like to convert the value in the number box into the answer next to it without any changes to the value. This should also include the variables NP0, NP1, and DP0 from t ...

Transforming a series of numbers separated by commas into numerical values

I need to process a list of comma-separated numbers using the math.js library in Node.js. Even though I successfully split the numbers into an array, the math.add() function requires individual integers instead of an array. I want to find a way to provid ...

What is the method for conducting an Ajax request?

Currently, I am deeply involved in a personal project to enhance my skills with Rails. The project involves developing a task management application that encompasses three primary states: todo, in progress, and done. After numerous days of trial and error, ...

Obtain a promise for the value directly from the hook

Attempting to be clever, I wanted to return a promise from a hook so I could await the value instead of waiting for the hook to give me the value after it resolves and reruns. However, I encountered an issue with the resolve part not firing correctly. Belo ...

Issue with popup display in React Big Calendar

I'm currently working on a calendar project using React-Big-Calendar, but I've run into an issue with the popup feature not functioning properly. <div className={styles.calendarContainer} style={{ height: "700px" }}> <C ...

Looking to transfer data between pages using node.js and ejs for database access?

I am aiming to showcase the logged in username and quiz points on each page after the user logs in, and to increase the user's score when quiz answers are correct. I'm considering creating a straightforward JavaScript-based quiz, and then updati ...

Guidelines for utilizing an image as a trigger for an if/else condition

I'm attempting to create a rock, paper, scissors-style game using jQuery. Here's how I envision it working: The player selects a picture by clicking on it, triggering the .click function. The computer then generates a random number between 1 an ...

Reorganize files with sequential numbers using Gulp, starting from the highest number within the directory

I am looking to create a gulp task that moves files from one folder to another while renaming them with sequential numbers. Here is the current task I have: var index = 0; gulp.task("jpg", function () { return gulp.src('img/new/**.{jpg,JPG}&ap ...

Access your own data, shared data, or designated data with Firebase rules

Seeking guidance on implementing firebase rules and queries for Firestore in a Vue.js application. Requirement: User must be authenticated User can read/write their own data entries User can read data with "visibility" field set to "public" User can rea ...

When using the React Material Tree Table, I expect any new row added to automatically expand by default in the table tree structure

<MaterialTable title="title" columns={columns} data={data} icons={tableIcons} parentChildData={(row, rows) => rows.filter((item) => item.id === row.productId)} /> ...

Encountering 'Illegal Invocation' error while running a basic script

Exploring the Speech Recognition API has been on my to-do list, so I decided to create a simple page that initiates recognition when clicking on the body element. Here is a snippet from my scripts.js file: var recognition = new window.webkitSpeechRecognit ...

Securing API data: Utilizing encryption techniques in express and nuxtjs to deter scraping efforts

I'm looking for a secure way to encrypt my API data in order to prevent users from viewing it in the network tab or as plain text within objects like window.__nuxt__. Currently, I am following these steps: Encrypting data on the back-end using a sec ...

Ensuring Uniqueness of Usernames in MongoDB

I'm currently working on a solution to check if a username already exists in my MongoDB database. If it does, I need to add a random number to it and then keep checking until a unique name is found. Below is the code snippet that I've been using ...

Generating keyframes spontaneously, unable to remove commas

Initially, I acknowledge that this code may not be the most elegant. I have simplified it to show only the essentials. My objective is to dynamically create a @-webkit-keyframe based on input, generate a class, and then apply that class so an object can c ...

What could be causing the jQuery to not function on the live website?

I am currently working with asp.net mvc2 and have developed a project featuring impressive slideshows and menus. While everything runs smoothly on my local machine, I encounter issues with jQuery not functioning properly upon publishing and viewing through ...

Retrieving image files from a database using jQuery (Binary Column)

I'm facing an issue with reading images from a database and displaying them on my website Whenever I retrieve an image from the Postgres database, which is stored in a binary field, it appears like this: '/9j/4AAQSkZJRgABAQAASABIAAD/4QBYRXhpZgA ...