Refreshing the connected value of an input upon making changes

I'm currently developing a simple to-do application. Each task is included in an input item within a Vue component called <list-item>. These <list-item> components are generated using a v-for directive that points to an array of tasks.

The goal is to enable users to edit each task input and have the changes reflected in the corresponding array item, not just in the input itself. While my @change event on the input element is triggering successfully, I'm uncertain about what steps to take next.

https://jsfiddle.net/xbxm7hph/

HTML:

<div class="app">

    <div class="add-control-area columns is-mobile is-multiline">

        <responsive-container>

            <div class="field is-grouped">
                <div class="control is-expanded">
                    <input class="input add-control-text" type="text" placeholder="New Task" v-model="newTask" v-on:keyup.enter="addTask">
                </div>
                <div class="control">
                    <a class="button is-white add-control-button" @click="addTask" :disabled="!isThereText">Add Task</a>
                </div>
            </div>

        </responsive-container>

        <responsive-container>

            <list-item v-for="task, index in tasks" :item="task" :index="index" @task-completed="completeTask(index)" @task-deleted="deleteTask(index)" ></list-item>

        </responsive-container>

    </div>

</div>

JS:

Vue.component('list-item', {
    props: ['item', 'index'],
    template: `<div class="task-wrapper">

<input class="task" :value="item" @change="updateTask()">

    <div class="task-control delete-task" @click="deleteTask()"></div>
    <div class="task-control complete-task" @click="completeTask()"></div>

</div>
  `,
  methods: {
    completeTask: function() {
      this.$emit('task-completed', this.index);
    },
    deleteTask: function() {
      this.$emit('task-deleted', this.index);
    },
    updateTask: function() {
      console.log('changed');
    }
  }
});

Vue.component('responsive-container', {
  template: `
    <div class="column is-4-desktop  is-offset-4-desktop is-10-tablet is-offset-1-tablet is-10-mobile is-offset-1-mobile">
            <div class="columns is-mobile">
                <div class="column is-12">
                  <slot></slot>
                </div>
            </div>
  </div>
  `
});

var app = new Vue({
    el: '.app',
  data: {
        tasks: [],
    completedTasks: [],
    newTask: ''
  }, 
  methods: {
    addTask: function() {
      if(this.isThereText) {
        this.tasks.push(this.newTask);
        this.newTask = '';
        this.updateStorage();
      }
    },
    completeTask: function(index) {
      this.completedTasks.push(this.tasks[index]);
      this.tasks.splice(index, 1);
      this.updateStorage();
    },
    deleteTask: function(index) {
      this.tasks.splice(index, 1);
      this.updateStorage();
    },
    updateStorage: function() {
      localStorage.setItem("tasks", JSON.stringify(this.tasks));
    }
  },
  computed: {
    isThereText: function() {
      return this.newTask.trim().length;
    }
  },

  // If there's already tasks stored in localStorage,
  // populate the tasks array
  mounted: function() {
    if (localStorage.getItem("tasks")) {
      this.tasks = JSON.parse(localStorage.getItem("tasks"));    
    }
  }
});

Answer №1

If you want to improve the reactivity of your <list-item> component in Vue, consider using the v-model directive instead of passing an item property directly. Remember to pass a reference from the array (tasks[index]) as task is a copy not bound to the array element:

<list-item v-for="task, index in tasks" v-model="tasks[index]"></list-item>

In the list item component definition, ensure you accept a value prop (used with

v-model</code) and set a data property <code>item
accordingly. Emit an input event on change to update the item value (expected by v-model):

Vue.component('list-item', {
  props: ['value'],
  template: `<div class="task-wrapper">
    <input class="task" v-model="item" @change="updateTask"></div>
  </div>
  `,
  data() {
    return {
      item: this.value,
    }
  },
  methods: {
    updateTask: function() {
      this.$emit('input', this.item);
    }
  }
});

View the implementation changes in this Fiddle link.


  • As highlighted by Bert Evans, remember to include a key attribute when using v-for in Vue components to avoid warnings:

     <list-item
       v-for="task, index in tasks" 
       :key="index"
       v-model="tasks[index]"
     ></list-item>
    
  • Consider storing items as objects with unique IDs rather than relying solely on array indices to prevent issues with changing indexes over time in complex applications.

Answer №2

To effectively handle the change event, you can include both the index and new value as parameters:

<input class="task" :value="item" @change="updateTask(index, $event)">

Then utilize them in your function like this:

updateTask: function(index, event) {
    console.log(index);          
    console.log(event.target.value);  
}

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 you include a key event handler that specifically looks out for the Space key being pressed?

When a user presses the Enter key (and button is in focus), the button opens. However, I would like to also open the link button when the user presses the space bar. Buttons should be activated using the Space key, while links should be activated with the ...

Step-by-step guide to adding products to your Supabase shopping cart

I have managed to insert a row into the "order" table with user information. Now, I want to individually add item details to a separate table named "order_storeItems" to create a relationship between the order and storeItems tables. I attempted using Pro ...

Ways to retrieve a concealed DOM element from a background window

I have been struggling to display a button that is located in the background window using the jQuery code below, but unfortunately it's not functioning as expected. On my webpage, I have a hidden button that should only be visible when a user adds a ...

Paused momentarily to allow user input

I am currently developing a new game where the player and enemies are stored inside objects with various properties. For example, each object includes: $player->health $player->attack (which represents attack power) Additionally, there is a PHP fun ...

Ensure consistency across browsers by disabling zoom functionality on touchpad inputs while still permitting scrolling actions

I am looking for a way to disable 2-finger zoom on trackpad "wheel" events while still allowing 2-finger scroll. On mobile, I have already disabled zoom with: <meta name="viewport" content="initial-scale=1, minimum-scale=1, m ...

When making an AJAX request to an ASP.NET web method, strange characters are appended to the end of the response text. This issue seems

I need assistance with the following code: $.ajax({ type: 'POST', contentType: 'application/json; charset=utf-8', url: location, data: JSON.stringify(ajaxData), dataType: 'xml', success: ca ...

Achieving Horizontal Alignment of jQuery within HTML utilizing CSS

I'm struggling to center the ASlider Jquery plugin () that I've added to my website's HTML code using CSS. No matter what I try, it stubbornly remains fixed to the left side of the page. I attempted using CSS properties like float, display, ...

Exploring the potential of Oracle Openscript in combination with Javascript using AngularJS,

I have encountered an issue while using Openscript on a form page with a clickable "save" button implemented as a div. Manually clicking the button triggers a javascript event that saves any changes made on the page. However, when I run the script, the but ...

Panel that collapses and increments its ID each time within my loop

I have a Collapsible Panel with this header, <div id="CollapsiblePanel1" class="CollapsiblePanel"> <div class="CollapsiblePanelTab" tabindex="0">Comments</div> <div class="CollapsiblePanelContent"> Content &l ...

Tips for making a website display in landscape mode rather than portrait orientation

As a newcomer to web design, I am curious if it is feasible to create a website that automatically rotates to landscape view when accessed on a mobile device. The current project I am working on is fluid in design, so this feature would greatly enhance t ...

When attempting to retrieve the data from a JSON file using an XMLHttpRequest, the result that is returned is [object object]

I am currently studying JSON and found a helpful guide on w3schools. Here is the code provided in the guide: https://www.w3schools.com/js/tryit.asp?filename=tryjson_ajax The guide also includes a sample JSON file: https://www.w3schools.com/js/json_demo.t ...

Reactjs is retrieving several items with just one click on individual items

I am having trouble getting only a single sub-category to display. Currently, when I click on a single category, all related sub-categories are showing up. For example, in the screenshot provided, under the Electronic category, there are two subcategories: ...

Creating: A Pair of Vue Components with Matching Sass Styles

As I ponder on the best way to structure my Vue components, I am faced with a dilemma. Two of my Vue components share the same sass code, yet they have different markup, state, and methods. I am seeking a solution to reduce repetition of sass code across t ...

Organizing Angular Material Styles using Namespacing

In an attempt to develop reusable components with Angular 1.4.3 and Angular-Material 1.0.5, the goal is to seamlessly integrate these components across various applications. However, a challenge arises as the Angular Material CSS contains styling rules th ...

having trouble transferring data from one angular component to another

I've been attempting to send data from one component to another using the service file method. I've created two components - a login component and a home component. The goal is to pass data from the login component to the home component. In the l ...

React and Express failing to display content

After relocating my React frontend folder to my collaborator's Express backend folder, here is our updated file structure. https://i.stack.imgur.com/i77XJ.png This code snippet represents app.js which is responsible for rendering the website. const ...

Unable to trigger a click on the submit button using JavaScript

I'm encountering difficulties in triggering a click using JavaScript on a Mailchimp pop-up subscribe form and I require your assistance. <!-- Title & Description - Holds HTML from CK editor --> <div class="content__titleDescripti ...

Vue.js failing to update when object property changes

<v-container class="text-center hyp-container pa-4"> <v-row> <button @click="toggleForm">Create new target</button> </v-row> <v-row> <v-dialog v-model="showConfirmDelet ...

What is the best way to extract the information from the checkbox in a MUI datatable?

I am struggling to transfer an array with checked values to another table in order to display only those values. How can I achieve this? I am relatively new to using react and I find it challenging to grasp how some of the functions and components work. I ...

retrieving the current value of a variable from a jQuery function

I've done my best to keep things simple. Here's the HTML code I've put together: <div id="outsideCounter"><p></p></div> <div id="clickToAdd"><p>Click me</p></div> <div id="in ...