vahdet
vahdet

Reputation: 6749

Vuetify - How to make setSelectionRange(int, int) work in v-textarea when its model is changed

I try to use the method setSelectionRange to change the position of the cursor in a vuetify v-textarea.

It works well when I do not manipulate the data element referred by the v-model attribute of the textarea. However, if I attempt to change the body first, and then apply the setSelectionRange method; the cursor moves directly to the end of the text.

I'm attaching a snippet of a simplified version. Once you hit backspace key on anywhere in the textarea and the cursor should move to index 2; but it moves to the end of the text instead.

If you remove this.body and backspace again, however, it peacefully moves to index 2.

new Vue({
  el: '#app',
  data: {
    body: ''
  },
  created () {
    this.body = 'I am initial body. Hit backspace on somewhere if you want!'
  },
  methods: {
    onBackspaceOrDeleteButtonKeydown (event) {
      // disable default behavior
      event.preventDefault()
      
      let bodyTextArea = this.$refs.pourBody.$el.querySelector('textarea')
      
      // COMMENT OUT THE NEXT LINE TO SEE THE CURSOR MOVES TO INDEX 2 ALWAYS
      this.body = 'I am changed body. My cursor should have moved to index 2 anyways, but it goes to the end like >'
      bodyTextArea.setSelectionRange(2, 2)
    }
  }
})
<!DOCTYPE html>
<html>

<head>
  <link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
  <link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>

<body>
  <div id="app">
    <v-app>
      <v-content>
        <v-container>
          <v-textarea 
            ref="pourBody"
            outline
            v-model="body"
            auto-grow rows="7"
            @keydown.delete="onBackspaceOrDeleteButtonKeydown"
          ></v-textarea>

        </v-container>
      </v-content>
    </v-app>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
</body>

</html>

The setSelectionRange does not like body change apparently.

How can I work around it?

Upvotes: 2

Views: 3487

Answers (2)

Dominic Lee
Dominic Lee

Reputation: 61

In addition to givehug's solution you can also do

this.$nextTick(() => {
   bodyTextArea.setSelectionRange(2, 2))
})

Upvotes: 4

givehug
givehug

Reputation: 2011

Wrap setSelectionRange into setTimeout, like so setTimeout(() => bodyTextArea.setSelectionRange(2, 2)). Value is rerendered by v-model after you set cursor to desired position and cursor position is reset. You have to make sure you call setSelectionRange afterwards.

Upvotes: 10

Related Questions