Kiee
Kiee

Reputation: 10771

event prevent default not working within VueJS instance

I'm trying to disable a form submission when the enter key is pressed. The approaches I've tried are listed below with the code and example demo.

EXAMPLE OF PROBLEM HERE

Desired outcome: Focus on the input, press down -> down -> enter and it should log the index of the record you have selected and stop there.

What's actually happening: It logs as expected, but then reloads the page immediately as the form submits.

HTML

<form action="/some-action" @submit.stop.prevent="prevent">
  <div class="auto-complete" v-cloak>
    <div class="ico-input">
      <input type="text" name="search" placeholder="Enter text" @keyup.prevent="handleKeypress">
    </div>
    <ul class="raw auto-complete-results">
      <li v-for="r in results" @click="loadSelection($index)" v-bind:class="{'selected': selectedIndex == $index}"><span>{{ r.name }}</span></li>
    </ul>
  </div>
</form>

JS

var autocomplete = new Vue({
  el: '.auto-complete',
  data: {
    results: [{name: 'swimming1'}, {name: 'swimming2'}, {name: 'swimming3'}, {name: 'swimming4'}, {name: 'swimming5'}, ],
    selectedIndex: -1,
  },
  methods: {
    handleKeypress: function(event) {
      event.preventDefault();
      event.stopPropagation();

      var key = event.which;

      if ([38, 40].indexOf(key) > -1) //handle up down arrows.
        this.arrowNavigation(key);

      else if (key == 13) //handle enter keypress
        this.loadSelection(this.selectedIndex);

      return false;
    },

    arrowNavigation: function(key, target) {
      if (key == 38) //up
        this.selectedIndex = this.selectedIndex - 1 < 0 ? 0 : this.selectedIndex - 1;
      if (key == 40) //down
        this.selectedIndex = (this.selectedIndex + 1) > (this.results.length - 1) ? 0 : this.selectedIndex + 1;
    },

    loadSelection: function(index) {

      if (index < 0 || index > this.results.length)
        return false;

      var selection = this.results[index];
      console.log("loading selection", index,selection);
    },

    prevent: function(event) {
      event.preventDefault();
      event.stopPropagation();
      return false;
    },
  }
})

I've tried various syntax approaches on both form/input (switching submit for keyup on the input)

I've also tried calling the following from with in the 2 event handlers aswell as returning false from them both.

The form still triggers a page reload no matter what I try. I can't see anything obviously wrong so I turn to stackoverflow to guide my eyes.

Thanks

Upvotes: 3

Views: 16993

Answers (4)

colemande
colemande

Reputation: 392

Try @keydown.enter.prevent I was having the same problem but I was using keyup

<input type="text" @keydown.enter.prevent="doSomething" />

You don't have to have a method either if you just want to stop the form from submitting just put @keydown.enter.prevent without a method.

<input type="text" @keydown.enter.prevent />

Upvotes: 0

Carlos Mori
Carlos Mori

Reputation: 408

Try this!

<form @submit.prevent>

Works for Vue2

Upvotes: 0

Linus Borg
Linus Borg

Reputation: 23968

This Answer to another question suggests that forms with a single input element always get submitted, not matter what you do.

And indeed adding another input (and hiding it) helped.

https://jsfiddle.net/Linusborg/Lbq7hf1v/1/

<div class="ico-input">
  <input type="text" name="search" placeholder="Enter text" @keyup.prevent="handleKeypress">
  <input type="text" hidden style="display:none;">
</div>

Browsers are stupid.

Upvotes: 4

Jason Tumusiime
Jason Tumusiime

Reputation: 317

Note that, anything outside of the el that you use to reference your Vue instance will not be recognized by vue no matter how correctly you define your event modifiers on your elements.

In your example you are referring to your Vue instance through the .auto-complete element which is a child of the form element which the submit event is bound to by default. Any event modifiers added to your form will never take effect. Try wrapping all your HTML in a div and reference vue through that, like so:

HTML

<div id="app">
    <!-- HTML/Vue Directives/Mustache here -->
    <form action="/some-action" @submit.stop.prevent="prevent"> 
        ... rest of your code ...
    </form>
</div>

JS:

var autocomplete = new Vue({
    el: '#app',
    data: { 
        ... rest of your js code ...
})

Also Vue devtools can be very useful when debugging such situations.

Upvotes: 2

Related Questions