Doonv
Doonv

Reputation: 35

When I use v-model on input element that has a parent with v-for, it only let's me put 1 character at a time

I'm working on a Todo List app with Vue. But I've encountered an issue when trying to implement the editing of the todo's names. This is my todo list template:

<div v-for="(todo, index) in todos" :key="todo.title" class="todo-item">
  <div>
    <!-- <div v-if="!todo.editing" class="item-label"
      @dblclick="editTodo(todo)" >{{ todo.title }}</div> -->
    <input
      @dblclick="todo.editing = true"
      @blur="todo.editing = false"
      @keydown.enter="todo.editing = false"
      class="item-edit"
      type="text" :readonly="!todo.editing ? true : null"
      v-model="todo.title">
  </div>
  <div class="remove-item" @click="removeTodo(index)">
    &times; 
  </div>
</div>

I originally had a div containing the todo's title. But now i've replaced it with a input, that's readonly but when doubled clicked becomes a normal input. But, when the input is editable, I can only input 1 character before it deselects. I believe the reason for why is because every time I input a character the todo list updates and because of that it deselects. How could I fix this?

Upvotes: 0

Views: 1064

Answers (2)

leo
leo

Reputation: 1

maybe a bit late, but for anyone else with a similar problem, its because the key is the todo.title he is changing with the input (v-model="todo.title")

Upvotes: 0

Ashraful Jannat
Ashraful Jannat

Reputation: 26

I modified your code a bit and hope the following solution helps you. I used two conditions to determine whether the title should be displayed or the input box. You can run the code snippet here and test if it serves your purpose. Let me know if you have any confusions.

new Vue({
      el: '#app',
      data: {
        todos: [
                    {
                        title: 'title- 1',
                        editing: true
                    },
                    {
                        title: 'title- 2',
                        editing: true
                    },
                    {
                        title: 'title- 3',
                        editing: false
                    }
                ],
                showInput: false,
                updateTitle: '',
                selectedIndex: -1
      },
      methods: {
        editTodo(index){
                if(this.todos[index].editing){
                    this.selectedIndex = index;
                    this.updateTitle = this.todos[index].title;
                    this.showInput = true;
                }
            },
            updateTodo(index){
                this.todos[index].title = this.updateTitle;
                this.showInput = false;
                this.selectedIndex = -1;
            },
            removeTodo(index){
                this.todos.splice(index, 1);
            }
      }
    })
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
        <div v-for="(todo, index) in todos" :key="todo.title" class="todo-item">
            <div v-if="index != selectedIndex" class="item-label" @dblclick="editTodo(index)" >
                {{ todo.title }}
                <span class="remove-item ml-2" @click="removeTodo(index)" style="cursor: pointer;"> &times; </span>
            </div>

            <input
                v-if="showInput && (index == selectedIndex)"
                class="item-edit"
                type="text"
                v-model="updateTitle"
                @blur="updateTodo(index)"
                v-on:keyup.enter="updateTodo(index)"
            >
        </div> 
    </div>

Upvotes: 1

Related Questions