Interacting with Vue.js: Exploring click events and the concept of "this"

I have a vue project with a to-do list feature, and I'm facing an issue when trying to use pop() to remove items from the list. Below is the relevant code snippet:

// components
Vue.component('todoitem', {
  template: "<li>Test Item</li>"
})

// app code
var app = new Vue({
  el: '#app',
  data: {
    todos: [
      { text: 'Sample Item 1' },
      { text: 'Sample Item 2' },
      { text: 'Sample Item 3' }
    ],
    button: {
      text: 'Hide'
    },
    seen: true
  },
  methods: {
    addItem: function() {
      let item = document.getElementById("list-input").value;
      let error = document.getElementById("error");
      if (item == "") {
        error.style.display = "block";
      } else {
        app.todos.push({ text: item });
        error.style.display = "none";
      }
    },
    removeItem: function() {
    this.todos.pop();
    },
    toggleSeen: function() {
      app.seen = !app.seen;
      app.button.text = app.seen ? 'Hide' : 'Show';
    }
  }
});
.todo-list {
  list-style-type: square;
}

.todo-list__delete {
  display: none;
}

li:hover .todo-list__delete {
  display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>

<div id="app">
  <ul class="todo-list">
    <li v-for="todo in todos">
      {{ todo.text }}
      <a v-on:click="removeItem" class="todo-list__delete" href="#">Delete</a>
    </li>
  </ul>

  <input type="text" id="list-input">
  <input type="submit" id="list-submit" v-on:click="addItem">
  <span id="error" style="color: red; display: none;">Please Enter Text</span>

  <ul>
    <todoitem></todoitem>
  </ul>

  <h2 v-if="seen">SEEN</h2>
  <button id="hide-seen" v-on:click="toggleSeen">{{ button.text }}</button>
</div>

When clicking the delete link, the expected behavior is for the corresponding item to be removed. However, I noticed that it actually removes items starting from the bottom instead.

I suspected that using this inside the removeItem function might be causing the problem by referencing the delete link rather than the <li> element itself. So, I attempted both of the following solutions:

removeItem: function() {
    this.todos.parentElement.pop();
}

And:

removeItem: function() {
    this.parentElement.todos.pop();
}

Unfortunately, neither approach worked as expected.

Can someone explain how this behaves in Vue.js?

Answer №1

Within the given context, when we refer to this, it pertains to the Vue component itself and not the DOM element. The statement this.todos is pointing to the todos array located within the component's data object. Additionally, the function pop is used to eliminate the last item in an array, hence resulting in the removal of the final element.

To remove a specific element from the array, you must provide relevant information to the removeItem function indicating which element needs deletion. Subsequently, the removeItem() function should be structured to eliminate that particular element from the todos array instead of simply removing the last element using pop. One way to accomplish this effectively would involve passing the array index to the removeItem function and then utilizing splice to extract that specified index from the todos array:

<li v-for="(todo, index) in todos">
  ...
  <a v-on:click="removeItem(index)">Delete</a>
</li>
removeItem: function(index) {
  this.todos.splice(index, 1);
},

The modified snippet considering the aforementioned change is provided below:

// components
Vue.component('todoitem', {
  template: "<li>Test Item</li>"
})

// app code
var app = new Vue({
  el: '#app',
  data: {
    todos: [
      { text: 'Sample Item 1' },
      { text: 'Sample Item 2' },
      { text: 'Sample Item 3' }
    ],
    button: {
      text: 'Hide'
    },
    seen: true
  },
  methods: {
    addItem: function() {
      let item = document.getElementById("list-input").value;
      let error = document.getElementById("error");
      if (item == "") {
        error.style.display = "block";
      } else {
        app.todos.push({ text: item });
        error.style.display = "none";
      }
    },
    removeItem: function(index) {
      this.todos.splice(index, 1);
    },
    toggleSeen: function() {
      app.seen = !app.seen;
      app.button.text = app.seen ? 'Hide' : 'Show';
    }
  }
});
.todo-list {
  list-style-type: square;
}

.todo-list__delete {
  display: none;
}

li:hover .todo-list__delete {
  display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>

<div id="app">
  <ul class="todo-list">
    <li v-for="(todo, index) in todos">
      {{ todo.text }}
      <a v-on:click="removeItem(index)" class="todo-list__delete" href="#">Delete</a>
    </li>
  </ul>

  <input type="text" id="list-input">
  <input type="submit" id="list-submit" v-on:click="addItem">
  <span id="error" style="color: red; display: none;">Please Enter Text</span>

  <ul>
    <todoitem></todoitem>
  </ul>

  <h2 v-if="seen">SEEN</h2>
  <button id="hide-seen" v-on:click="toggleSeen">{{ button.text }}</button>
</div>

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

Get a Blob as a PNG File

Hope you had a wonderful Christmas holiday! Just to clarify, I am new to JS and may make some unconventional attempts in trying to download my Blob in PNG format. I am facing an issue with exporting all the visual content of a DIV in either PDF or image ...

Error occurs when the asynchronous function is invoked and completes, or when the callback is not a valid function when called on the

Attempting to create a function that calls other functions: copy = () => { copyHtml(); copyCss(); copyJs(); copyImg(); } exports.copy = copy; When using gulp copy, the function runs but an error is encountered: The following tasks did ...

Retrieving the chosen value when there is a change in the select tag

Building a shop and almost done, but struggling with allowing customers to change product quantities in the cart and update prices dynamically. I've created a select-tag with 10 options for choosing quantities. I'd like users to be able to click ...

Switching between Login Form and Register Form in VueJS template

Recently, I attempted to switch between the 'Login Form' and 'Register Form' using code that I found on codepen Flat HTML5/CSS3 Login Form. While the code functioned properly on its own, when integrated into a Vue Template, the form fai ...

Uniqid in React fails to generate unique IDs

Currently working on creating my first react project and developing a todo list. I have incorporated the uniqid generator into my todo object, but it seems to be returning an empty id rather than a random one. Oddly enough, if I move the todo state outsi ...

What is the best way to assign a value to process.env within an npm script?

After creating a new Vue app (using Vite) with npm init vue@latest and selecting Playwright for e2e tests, the configuration file was generated with a field for setting headless mode: const config: PlaywrightTestConfig = { // ... use: { // ... ...

Is it better to utilize angular's $interval or a promise to execute code upon completion of an api call?

I am facing an issue with a slow api call in my code. $http.jsonp(url, { params: { 'client': 'translate_about', 'alpha': 1, 'hl': 'en' } }) .success(function (data) { ...

How can I send the special $event variable as an argument in Vue?

When using Vue, I am trying to listen for a change event and pass the $event variable to an action. Here is how I have set it up in my template: <template> <div> <span>Filter Todos:</span> <select @change="filter ...

The specified subpath './lib/tokenize' does not match any defined "exports"

As a newcomer to React, I've been facing some challenges while trying to get started. Despite searching on Google and other platforms, I couldn't find a solution to my problem. I was attempting to run code from a YouTube channel called Lama Dev b ...

Avoid an issue where the v-btn (floating action button) placed at the top in an absolute position does not extend beyond the boundaries of the v-card in

I'm struggling with keeping this visible when it exceeds the component's boundaries. Any tips on how I can achieve that? Thanks in advance for your assistance. <v-card> <v-btn @click="dialog = false" fab small absolute top right c ...

`Discover the latest version of Tailwind using JavaScript or PHP`

My setup includes Laravel v8.81.0 (PHP v8.1.2), Vue v3.2.30, and Tailwind https://i.sstatic.net/fVbJB.png I am looking to fetch the Tailwind version in JavaScript similar to how I can get the Vue version using: //app.js require('./bootstrap'); ...

Creating a blurred background effect when a React portal is presented

I have implemented React portals to display a modal popup after the form is submitted. However, I am facing an issue with blurring only the background while showing the modal, similar to what is shown in picture 2. Initially, I tried using document.body.st ...

What is the best way to retrieve the second element based on its position using a class name in Jquery?

DisablePaginationButton("first"); The statement above successfully disables the first element that is fetched. DisablePaginationButton("second"); ===> not functioning function DisablePaginationButton(position) { $(".pagination a:" + position).ad ...

Tips for modifying fullcalendar's renderEvents handler to include custom code

Currently, I am working with fullcalendar 1.6.3 in conjunction with Drupal 7 (which is why I have to stick with version 1.6.3 for now). Every time the calendar view changes through ajax requests - whether moving forward or backward in time or switching bet ...

Is there a way to modify the image of a single face in a Cubemap using THREE.js?

In my project, I am attempting to showcase a panorama using cubemaps by initially loading and displaying 6 low-quality images on the cubemap. Achieving this can be easily done through the following code: var urls = [ 'path/to/low-q-pos-x.png', & ...

Tips for managing a Yes No dialogue box that appears when a button is clicked with JavaScript

When the user clicks on the update button in my form, I want to prompt them with a message asking if they want to delimit the record using Yes and No buttons. If they click on Yes, then the code to delimit the record should be executed; otherwise, just upd ...

Storing mySQL Database Content in a Javascript Array

I'm working on building a slideshow by fetching database information and storing it in a JavaScript array. Currently, I am using the jQuery AJAX function to retrieve data from a separate PHP file. Below is my PHP code: mysql_connect('x', &a ...

The Node.js application appears to be unresponsive on the designated port

When specifying port 30000, my app ends up listening on a different port unexpectedly. Below is the code snippet I have written: var express = require('express'); var bodyParser = require('body-parser'); var path = require('path& ...

Encountering the "JavaScript heap out of memory" error is a frequent occurrence when running npm scripts

Encountering issues with running npm and seeing the error message FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory. This problem arose after installing node.js&npm on my new PC. The only npm command that functions pro ...

Utilizing Google Maps to generate outcomes for an online platform

My approach with Google Maps is a bit unconventional. Instead of rendering images, I aim to execute JavaScript code that processes data and returns a text response. However, I soon realized that running JavaScript as a remote web service might not be pos ...