Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Click-and-edit text input with Vue

I'm looking for a click-and-edit Vue component.

I've found a fiddle and made some edits. It works like this:

enter image description here

The fiddle is here.

The problem: I need an additional click to make the input focused. How can I make it focused automatically?

The code from the fiddle. HTML:

<div id="app">
Click the values to edit!
  <ul class="todo-list">
    <li v-for = "todo in todos">
      <input v-if = "todo.edit" v-model = "todo.title"
      @blur= "todo.edit = false; $emit('update')"
      @keyup.enter = "todo.edit=false; $emit('update')">
            <div v-else>
        <label @click = "todo.edit = true;"> {{todo.title}} </label>
      </div>
    </li>
  </ul>


</div>

JS:

new Vue({
  el: '#app',
  data: {
    todos: [{'title':'one value','edit':false},
                  {'title':'one value','edit':false},
                    {'title':'otro titulo','edit':false}],
    editedTodo: null,
    message: 'Hello Vue.js!'
  },
  methods: {
    editTodo: function(todo) {
      this.editedTodo = todo;
    },
  }

})
like image 648
Andrey Moiseev Avatar asked Jul 24 '18 16:07

Andrey Moiseev


3 Answers

You can use a directive, for example

JS

new Vue({
  el: '#app',
  data: {
    todos: [
      { title: 'one value', edit: false },
      { title: 'one value', edit: false },
      { title: 'otro titulo', edit: false }
    ],
    editedTodo: null,
    message: 'Hello Vue.js!'
  },
  methods: {
    editTodo: function (todo) {
      this.editedTodo = todo
    }
  },
  directives: {
    focus: {
      inserted (el) {
        el.focus()
      }
    }
  }
})

HTML

<div id="app">
    Click the values to edit!
    <ul class="todo-list">
        <li v-for="todo in todos">
            <input
                v-if="todo.edit"
                v-model="todo.title"
                @blur="todo.edit = false; $emit('update')"
                @keyup.enter="todo.edit=false; $emit('update')"
                v-focus
            >
            <div v-else>
                <label @click="todo.edit = true;"> {{todo.title}} </label>
            </div>
        </li>
    </ul>
</div>

You can find more info here https://v2.vuejs.org/v2/guide/custom-directive.html

like image 57
AitorDB Avatar answered Oct 07 '22 21:10

AitorDB


With @AitorDB's help I have written a Vue component for this, I call it Click-to-Edit. It is ready to use, so I'm posting it.

What it does:

  • Supports v-model
  • Saves changes on clicking elsewhere and on pressing Enter

ClickToEdit.vue: (vue 2.x)

<template>
  <div>
    <input type="text"
           v-if="edit"
           :value="valueLocal"
           @blur.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
           @keyup.enter.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
           v-focus=""
             />
        <p v-else="" @click="edit = true;">
          {{valueLocal}}
        </p>
    </div>
</template>

<script>
  export default {
  
  props: ['value'],
  
  data () {
  return {
      edit: false,
      valueLocal: this.value
    }
  },
  
  watch: {
    value: function() {
      this.valueLocal = this.value;
    }
  },
  
  directives: {
    focus: {
      inserted (el) {
        el.focus()
      }
    }
  }
  
}
</script>

Edit for 3.x: [Breaking changes between 2.x and 3.x]

  • remove .native from the event handlers
  • change the focus hook to mounted as described in Custom Directives 3.x.
like image 43
Andrey Moiseev Avatar answered Oct 07 '22 22:10

Andrey Moiseev


Built on @Masen Furer's work. I added some protection to handle when a user deletes all of the data. There is probably a way to accomplish this using "update" but I couldn't get it working. I also added the ability to hit escape and abandon any changes.

<template>
  <span>
    <input type="text"
           v-if="edit"
           :value="valueLocal"
           @blur="save($event);"
           @keyup.enter="save($event);"
           @keyup.esc="esc($event);"
           v-focus=""/>
        <span v-else @click="edit = true;">
          {{valueLocal}}
        </span>
    </span>
</template>

<script>
  export default {
  
  props: ['value'],
  
  data () {
  return {
      edit: false,
      valueLocal: this.value,
      oldValue: (' ' + this.value).slice(1)
    }
  },
  methods: {
      save(event){
        if(event.target.value){             
            this.valueLocal = event.target.value; 
            this.edit = false; 
            this.$emit('input', this.valueLocal);
        }
      },
      esc(event){
          this.valueLocal = this.oldValue; 
          event.target.value = this.oldValue;
          this.edit = false; 
          this.$emit('input', this.valueLocal);
      }
  },
  watch: {
    value: function() {
      this.valueLocal = this.value;
    }
  },
  
  directives: {
    focus: {
        inserted (el) {
            el.focus()
        }
    }
  }
  
}
</script>
like image 1
Seamus Avatar answered Oct 07 '22 21:10

Seamus