VueJS: @keydown, @keyup, and this.$refs works with input, but not with md-textarea
Asked Answered
C

1

13

I have successfully completed a basic speed typing game using vue.js. For the "typing box", I used <input>, and everything worked fine. However, when I added more levels to my game, with longer sentences for the user to type, I have identified the need to change my <input> element into <md-textarea> - a vue.js component.

THE PROBLEM:

The following attributes that were working fine with <input> won't work as expected with <md-textarea>:

  • @keyup="checkAnswer()"
  • @keydown="keymonitor"
  • @keydown.ctrl.86="noPaste" (prevents paste via Ctrl+V)
  • @keydown.shift.45="noPaste" (prevents paste via Shift+Insert)
  • ref="typeBox" (allows focusing on the element via this.$refs.typeBox[0].focus())

Please refer to the codes below.

Am I missing anything? Please help me debug this. Thank you.

NOTE: I know it throws an error here in SO snippet feature, but that error does not exist in my development environment.

export default {
  name: 'game',

  data () {
    return {
      disabledKeys: ['ArrowLeft', 'Home']
    }
  },

  methods: {
    /**
     * prevents pasting via 'Ctrl + V' (@keydown.ctrl.86) and 'Shift + Insert' (@keydown.shift.45)
     */
    noPaste: function (event) {
      event.preventDefault()
    },

    /**
     * Monitors every single key input in the answer text box.
     *
     * Prevents using of disabled keys in the text input.
     */
    keymonitor: function (event) {
      if (this.disabledKeys.indexOf(event.key) >= 0) {
        event.preventDefault()
      }
    }, /*END keymonitor*/
    
    startTimer () {
      this.timer.id = setInterval(this.updateTimer, 1000)
      
      this.$nextTick(() => {
        this.$refs.typeBox[0].focus()
      })

      this.game.status = 'in progress'
    }, /*END startTimer*/
  } /* END methods */
} /* END export default */
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.4/vue.min.js"></script>
<template>
  <md-input-container md-flex="100">
  
    <!-- this one is working -->
    <input id="typeBox" autocomplete="off" placeholder="Type here..." ref="typeBox" v-model="answer" @keydown="keymonitor" @keydown.ctrl.86="noPaste" @keydown.shift.45="noPaste"/>
    
    <!-- this one is not working -->
    <md-textarea id="typeBox" autocomplete="off" placeholder="Type here..." ref="typeBox" v-model="answer" @keydown="keymonitor" @keydown.ctrl.86="noPaste" @keydown.shift.45="noPaste"></md-textarea>
    
  </md-input-container>
</template>
Crafty answered 16/3, 2017 at 4:38 Comment(2)
The problem is that <md-textarea> does not emit those events (keydown). As far as I can see, it only emits change and input. If you really need the keydown event support, you may need to simply use a <textarea> and style it yourselfSupporter
Stupid me, why didn't I think of that?! ... especially when there's no styling issue at all when using <textarea>. Thanks a lot for pointing this out. Can you post your comment as an answer so I can vote it up? I'm keeping this question here, just in case someone else figures out a solution for <md-textarea> itself.Crafty
F
25

You can bind functions to the native events of the root element of a component by using the .native modifier. See the documentation here.

In your case, you can add native event handlers to the <md-textarea> component like so:

<md-textarea 
  id="typeBox" 
  autocomplete="off" 
  placeholder="Type here..." 
  ref="typeBox" 
  v-model="answer" 
  @keydown.native="keymonitor" 
  @keydown.native.ctrl.86="noPaste" 
  @keydown.native.shift.45="noPaste"
></md-textarea>
Frug answered 16/3, 2017 at 13:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.