15

I am trying to call method on pressing enter key but it's not working. Code is as below.

<template>
  <div>
    <button @click="callEvent" @keyup.enter="callEvent"> Click </button>
  </div>
</template>

<script>
export default{
  methods:{
    callEvent(){
      console.log("Event called");
    }
  }
}
</script>
Erick Petrucelli
  • 14,386
  • 8
  • 64
  • 84
Hitendra
  • 3,218
  • 7
  • 45
  • 74
  • I'm not sure `@keyup.enter` is valid on button, as button has no `keyup` event. it should be used for inputs – Shahar Galukman Oct 26 '17 at 13:09
  • It *does* work in the sense that `callEvent` is fired on the keyup event. https://jsfiddle.net/12um7eeb/ What is the actual problem? As others have mentioned, Enter key's keydown event will trigger the click event. So the method fires twice when you press Enter. Once on keydown and once on keyup. Are you trying to prevent that? – thanksd Oct 26 '17 at 13:53
  • @thanksd, Enter key event is fired but i am getting error on app.callEvent(); – Hitendra Oct 26 '17 at 13:58
  • The code you've provided works fine and gives no errors, see my fiddle. You need to provide better context. – thanksd Oct 26 '17 at 14:00

4 Answers4

13

The click event already triggers with the ENTER key (it also triggers with Space in some browsers, like Chrome for desktop). So, your code only needs a @click="callEvent" and everything works well since the focus is already on the button:

var app = new Vue({
  el: "#app",
  methods: {
    callEvent() {
      console.log("Event called");
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<div id="app">
  <button @click="callEvent">Enter</button>
</div>

If you want that any ENTER triggers the button even if it isn't with focus, you should bind the event to the window object, which can be made inside the mounted handler:

var app = new Vue({
  el: "#app",
  methods: {
    callEvent() {
      console.log("Event called");
    }
  },
  mounted() {
    window.addEventListener('keyup', function(event) {
      if (event.keyCode === 13) { 
        app.callEvent();
      }
    });
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<div id="app">
  <button>Enter</button>
</div>

Remember that if you're using Single File Components, the instance is exposed by the this keyword, which can be used to call component methods inside the desired handler:

export default {
  methods: {
    callEvent() {
      console.log('Event called')
    }
  },
  mounted() {
    window.addEventListener('keyup', event => {
      if (event.keyCode === 13) { 
        this.callEvent()
      }
    })
  }
}
Erick Petrucelli
  • 14,386
  • 8
  • 64
  • 84
  • I am using vue router so getting error "Uncaught ReferenceError: app is not defined" – Hitendra Oct 26 '17 at 13:49
  • In my example, `app` is the Vue instance. Since you're using *Single File Components*, each component instance is exposed with the `this` keyword: `this.callEvent()`. I've updated may answer to clarify that. – Erick Petrucelli Oct 26 '17 at 14:39
  • 1
    `this` referencing the Vue instance is not specific to single-file components. You could do the same thing in your second example. – thanksd Oct 26 '17 at 14:43
  • @thanksd, I believe that the meaning of `this` is out of scope for this kind of question. Yes, I could use it in the second example along with an *Arrow Function*, what I haven't used because it's a code snippet to be run by browsers and IE doesn't understand it. With Single File Components, we can use it without fear. – Erick Petrucelli Oct 26 '17 at 15:51
  • 1
    I agree. I think your last example is out of scope and misleading. Side note: you can enable Babel in your code snippet so that arrow functions can be run in IE. – thanksd Oct 26 '17 at 19:19
4

Buttons don't have keyup event on them. Even when you have focus on the button, and hit enter, it will be considered a click event, instead of keyup.enter.

Try binding the event to an input and it'd work.

Alternatively, you could use jQuery (or Plain JS) to bind for keydown event on the body element, and trigger the Vue method by calling app.callEvent().

var app = new Vue({
  el: "#app",
  methods: {
    callEvent() {
      console.log("Event called");
    }
  },
  mounted() {
    var self = this;
    window.addEventListener('keyup', function(event) {
      if (event.keyCode === 13) { 
        self.callEvent();
      }
    });
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<div id="app">
  <template>
  <div>
    <button @click="callEvent"> Click </button>
  </div>
  <input type="text"  @keyup.enter="callEvent" />
</template>

</div>

Updated to use mounted instead of relying on jQuery - as per Erick Petrucelli's answer as it allows referring to the Vue component without the global variable.

Nisarg Shah
  • 14,151
  • 6
  • 34
  • 55
  • is there any other solution? I have page in which there is no input and if user hit enter it should call method. – Hitendra Oct 26 '17 at 13:17
  • something like detect the enter key press event and call method? – Hitendra Oct 26 '17 at 13:18
  • If the user has focus on the button, then there's no issue - as it would trigger the click event anyway. Else, you can try using jQuery to bind to the `body` element, and trigger the Vue method by calling `app.callEvent()` from the jQuery event listener. Do you want me to show that in the answer? – Nisarg Shah Oct 26 '17 at 13:22
  • @Hitendra Updated the answer. – Nisarg Shah Oct 26 '17 at 13:27
  • see the updated code. Getting error Uncaught ReferenceError: app is not defined – Hitendra Oct 26 '17 at 13:41
  • I am using vue router. Don't know how to get app instance in vue file. – Hitendra Oct 26 '17 at 13:42
  • I just noticed, Erick's answer. I like binding to the event through `mounted` - as it would let you access the component directly. Can you try with the updated answer? Or, maybe provide a working fiddle? – Nisarg Shah Oct 26 '17 at 14:14
4

I experienced inconsistent results when using native JS with window.addEventListener. VueJS natively supports modifying behavior for keyboard events https://v2.vuejs.org/v2/guide/events.html#Key-Modifiers

This also worked a lot better in my case due to needing separate behavior for the tab key.

Your input can look like this with custom modifiers on each key up|down

    <input 
        type="text" 
        class="form-control" 
        placeholder="Start typing to search..." 
        v-model="search_text" 
        @focus="searchFocus" 
        @blur="searchFocusOut"
        v-on:keyup.enter="nextItem"
        v-on:keyup.arrow-down="nextItem"
        v-on:keyup.arrow-up="nextItem"
        v-on:keydown.tab="nextItem"
    >

Then inside NextItem you can reference the event, and get each key.. or write a separate function for each key modifier.

tony19
  • 125,647
  • 18
  • 229
  • 307
Jeff Beagley
  • 945
  • 9
  • 19
1
@keyup.enter="callEvent"

change to

@keypress.enter.prevent="callEvent"
    <template>
      <div>
        <button @click="callEvent" @keypress.enter.prevent="callEvent"> Click </button>
      </div>
    </template>

Ref: https://github.com/vuejs/vue/issues/5171

bguiz
  • 27,371
  • 47
  • 154
  • 243