What is the best way to add an element conditionally within a specific Vue Component scope?

I've been working on creating a Component for titles that are editable when double-clicked. The Component takes the specific h-tag and title as props, generating a regular h-tag that transforms into an input field upon double click. It's functioning properly with single instances on a page, but encounters issues when multiple Components are utilized due to improper scoping. I'm currently stuck on how to resolve this issue, here is the code snippet:

<template>
  <div class="edit-on-click">
    <input
      :class="sizeClass"
      type="text"
      v-if="edit"
      v-model="editedTitle"
      @blur="finishEdit"
      @keyup.enter="finishEdit"
      v-focus="true"
    />
    <span v-show="!edit" @dblclick.prevent="edit = true"></span>
  </div>
</template>

Struggling with scoping in the mounted hook:

  mounted() {
    let node = document.createElement(this.size); // Accepts h-tag (h1, h2 etc.)
    let titleText = document.createTextNode(this.finalTitle); // Accepts title

    node.appendChild(titleText);
    node.classList.add("editable-title");

    // This causes issues with multiple components on the page
    document.getElementsByTagName("span")[0].appendChild(node);
  },

Any suggestions on how to efficiently scope this? Thanks in advance!

Answer №1

When using Vue, it is recommended to avoid creating DOM elements in the traditional way as much as possible to prevent race conditions where Vue is not aware of these elements that you may want to be reactive at some point (such as the <span> double-clicking in your case).

Instead, consider dynamically switching between different headings using the <component> element and the v-bind:is property. Here is an example:

Vue.component('EditableHeading', {
  template: '#editable-heading',

  props: {
    size: {
      type: String,
      default: 'h1'
    },
    value: {
      type: String,
      required: true
    }
  },

  data() {
    return {
      editing: false
    }
  },

  methods: {
    confirm(e) {
      this.$emit('input', e.target.value);
      this.close();
    },
    start() {
      this.editing = true;
      
      this.$nextTick(() => {
        this.$el.querySelector('input[type="text"]').select();
      });
    },
    close() {
      this.editing = false;
    }
  }
})

new Vue({
  el: '#app',

  data: () => ({
    titleList: [],
    text: 'New Title',
    size: 'h3'
  }),

  methods: {
    addNewTitle() {
      this.titleList.push({
        text: this.text,
        size: this.size
      });
    }
  }
})
.edit-on-click {
  user-select: none;
}

.heading-size {
  margin-top: 1rem;
  width: 24px;
}

p.info {
  background-color: beige;
  border: 1px solid orange;
  color: brown;
  padding: 4px 5px;
  margin-top: 2rem;
}
<script src="https://vuejs.org/js/vue.min.js"></script>

<div id="app">
  <editable-heading 
    v-for="(title, index) of titleList" :key="index" 
    v-model="title.text" 
    :size="title.size">
  </editable-heading>

  <div>
    <label>
      Heading size: 
      <input v-model="size" class="heading-size" />
    </label>
  </div>
  <div>
    <label>
      Title: 
      <input v-model="text" />
    </label>
  </div>
  <div>
    <button @click="addNewTitle()">Add new title</button>
  </div>

  <p class="info">
    [double-click]: Edit <br />
    [enter]: Confirm <br />
    [esc/mouseleave]: Cancel
  </p>
</div>

<script id="editable-heading" type="text/x-template">
  <div class="edit-on-click">
    <input 
      type="text" 
      v-if="editing" 
      :value="value" 
      @blur="close" 
      @keydown.enter="confirm" 
      @keydown.esc="close" />

    <component :is="size" v-else @dblclick="start">{{value}}</component>
  </div>
</script>

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

How can I toggle the visibility of a div based on whether a variable is defined or not?

How can I display a specific div on my webpage only when certain variables in PHP pull out a specific result from a database? I attempted to use the code snippet below, but it's not working as expected. Can someone provide guidance on how to achieve ...

Using the `ssh2` module in Node.js without specifying a specific object

When you use require('ssh2') in Node.js without a specific object (e.g. require('ssh2').Client), what does it imply? I'm in the process of understanding some code and still new to learning Node.js. Here's how it is being used: ...

Create a dynamic form using JSON data and the Material UI library

Looking for assistance in creating a dynamic form on Next.js by parsing JSON files and generating the required components from the JSON data. Additionally, seeking guidance on utilizing the Material UI library for styling. Any examples or help would be g ...

Your search parameter is not formatted correctly

I am currently working on filtering a collection based on different fields such as name by extracting the values from the URL parameters. For example: http://localhost:3000/patient?filter=name:jack I have implemented a method to retrieve and convert these ...

Having trouble extracting the video ID from a Youtube feed XML with jQuery

My goal here is quite simple - I have created a search result using a URL string with the YouTube API. When you visit the URL, you can view the XML returned without any issues. The specific URL is: https://gdata.youtube.com/feeds/api/videos?q=all the smal ...

What are some solutions for resolving a TypeError in the created hook of a Vue.js application

Oops, there seems to be an error: vue.js:597 [Vue warn]: Error in created hook: "TypeError: handlers[i].call is not a function" found in ---> <StageExecs> vue.js <div id="vue-job"> <div class="row"> <h3>test</ ...

The event on the full calendar is stuck in place and will not budge

function moveEvent(event, delta, revertFunc) { console.log(event.title + " has been moved to " + event.start.format()); var page = '../include/UpdateCalendarEvent.php'; $("#dialog") .data('start', event.start.format ...

The issue with the Hidden Content feature in the Slick Carousel is that it does not function correctly on the

There are some related topics worth exploring, such as: Slick carousel center class not working when going from last item to first item Despite trying various solutions, the issue still persists in my code. My goal is to have each item displayed in the ce ...

Partial data is being received from the Ajax call

I currently have a textarea and a button on my webpage <textarea id="xxx" class="myTextArea" name="Text1" cols="40" rows="15">@ViewData["translation"]</textarea> <input type="button" id="convert-btn" class="btn btn-primary" value="Convert t ...

Implement a jQuery loading animation triggered by scrolling down the page

Can anyone offer guidance on how to trigger an animation as you scroll down a webpage? I've come across this feature while browsing through this website: I would love to include code examples, but I'm unsure of where to start with implementing t ...

Display the initial page and activate the first navigation button when the page loads

Greetings to everyone. I am new to the world of jquery and currently in the process of learning. This is my script: <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"> </script> <script> $(function () { $ ...

JavaScript Linked List Operations: Issues with the removeHead() and contains() Functions

Incorporating ES6 syntax, the challenge is to construct a linked list and subject it to an npm linter test. Below is the code implementation: class LinkedList { constructor() { this.head = null; this.tail = null; // Do not alter anything wit ...

What could be the reason for encountering TypeScript within the Vue.js source code?

While exploring the vue.js source code, I stumbled upon some unfamiliar syntax that turned out to be TypeScript after further investigation. What baffled me was finding this TypeScript syntax within a ".js" file, when my understanding is that TypeScript ...

Restore checkbox to default setting

Is it possible to reset checkboxes in a form back to their initial status using javascript, PHP, jQuery, or any other method? Here is the code I am currently using: <form method="POST> <input type="text" name="name" id="name" value="default val ...

Issue with Javascript Promise causing failure to populate list with objects

app.get('/zones/:id/experiences', function(req,res) { var zone_key = req.params.id; var recent = []; var ref = firebase.database().ref('participants/'+zone_key+'/experiences'); ref.on("value", function(snapshot) { ...

Arrange the columns in Angular Material Table in various directions

Is there a way to sort all columns in an Angular material table by descending order, while keeping the active column sorted in ascending order? I have been trying to achieve this using the code below: @ViewChild(MatSort) sort: MatSort; <table matSort ...

I am working on developing a CRUD application using Vue.Js, but I'm facing difficulties in adding new users to

I encountered an error while attempting to insert data into the database. The error message states that "Property or method 'saveUser' is not defined on the instance but referenced during render." Below is the code snippet: <script> impor ...

Retrieving data from a remote PHP server using JavaScript

I am currently working on two separate websites. Site A is coded using only HTML and JavaScript, while site B utilizes PHP. I am trying to figure out a way to access variables from site B within site A. For example: The code for site A looks something li ...

Making a dropdown menu spin using Jquery and Javascript

I am in need of a unique solution for a dropdown menu that appears rotated 90 degrees anticlockwise. The goal is to have the dropdown select "button" text displayed vertically, with the options sliding out in a similarly rotated, sideways manner featuring ...

Generate a series of rotations ranging from -60 to 60 using d3.cloud

I need help replicating the word cloud feature found on for my website. After studying examples and referencing a Stack Overflow answer, I put together the following code: var fill = d3.scale.category20(); var layout = d3.layout.cloud() .size([900, ...