18

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;
    },
  }

})

3 Answers 3

20

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

Sign up to request clarification or add additional context in comments.

Comments

11

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.

4 Comments

I tried the component you wrote, and I got errors like errors So I removed the .native part modifications, and it works now. I'm not sure what '.native' does though, but it works after I remove it lol.
Awesome little component! Thanks so much. Following up on HelloBill's comment. I am using Vue2 and also had to remove the .native for it to respond to enter or blur events. But after doing that it works like a charm.
This is great. The answer could be better if it had an example for how to use this, as I took some time to figure it out.
Part of my implementation for other users: in the <template>: <ClickToEdit @input="onNameChange" :value="user.name">{{ user.name }}</ClickToEdit>, in the <script>: import ClickToEdit from '@/components/common/form/ClickToEdit'
1

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>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.