0
votes

I would like to live replace whitespaces with underscore _ in file name input in bootstrap-vue. But if I add a white space not at the end of input then formatter will move the cursor position to end of input. How to replace whitespaces without changing cursor position?

I tried:

<div class="form-group row">
    <label class="col-6 col-md-4 col-lg-3 col-xl-3">File name</label>
    <div class="col-6 col-md-8 col-lg-9 col-xl-9">
        <b-input-group v-if="viewModel.offer">
            <b-form-input ref="fileName" type="text" :formatter="formatter"></b-form-input>
            <b-input-group-append>
                <b-button variant="dark" v-b-popover.hover.top="'Download'" v-on:click=".."><i class="fas fa-arrow-circle-down"></i></b-button>
            </b-input-group-append>
        </b-input-group>
    </div>
</div>

with:

            formatter(value, event) {                
                const pos = event.target.selectionStart - 1
                const nfileName = value.replace(/\s+/g, '_');
                if (nfileName !== value) {
                    this.$nextTick(() => {
                        event.target.selectionEnd = pos
                    })
                }
                return nfileName;
            }

but there the selectionStart value is equal selectionEnd, so that actual position is unknown.

1

1 Answers

1
votes

Try using setTimeout instead of $nextTick. setTimeout, should be run after the input has been allowed to render the new value (and moving the cursor).

I personally found this explaning pretty good, about how the logic functions. http://www.hesselinkwebdesign.nl/2019/nexttick-vs-settimeout-in-vue/

new Vue({
  el: '#app',
  data() {
    return {
      text: ''
    }
  },
  methods: {
    formatter(value, event) {
      const {
        target: {
          selectionEnd,
          selectionStart
        }
      } = event

      setTimeout(() => {
        event.target.selectionStart = selectionStart;
        event.target.selectionEnd = selectionEnd;
      })

      return value.replace(/\s+/g, '_');
    }
  }
})
<link href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/[email protected]/dist/bootstrap-vue.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bootstrap-vue.js"></script>

<div id="app">
  <b-input v-model="text" :formatter="formatter"></b-input>
</div>