vue.jsinputv-model

Vue v-model issue when using a computed setter


I want to create an input field that the user can fill out. The catch is that I don't want them to fill this field in with special characters. Currently, I have this html setup:

    <input class="rc-input-editing" id="bioInput" type="text" v-model="wrappedBioName">

And this Vue.js setup (As you can see, I'm trying to approach this problem using a computed setter) :

    data () {
      return {
        newBioName: '',
      }
    },
    computed: {
      wrappedBioName: {
        get () {
          alert('getting new name!')
          return this.newBioName
        },
        set: function (newValue) {
          const restrictedChars = new RegExp('[.*\\W.*]')
          if (!restrictedChars.test(newValue)) {
            this.newBioName = newValue
          }
        }
      }

Currently, my issue is that the client is able to continue filling out the text input field, even when this.newBioName isn't updating. In other words, they are able to enter special characters into the input field, even though the this.newBioName isn't being updated with these special characters.

This behavior is different than what I'm expecting, given my current understanding of v-model. Based on what I've read until now, v-model binds the input element to some vue instance data, and that vue instance data to the input element (two way binding). Therefore, I'm expecting that the text in the text input field will directly match the value of this.newBioName.

Clearly, I'm missing something, and would appreciate a second pair of eyes!


Solution

  • Vue.js two way binding system doesn't work as you expected. Each binding process works one way each time. So, the thing you should do is not to let the input text change.

    Try keypress event instead of computed property like this:

    <input class="rc-input-editing" id="bioInput" type="text" v-model="newBioName" @keypress="nameKeyPressAction">
    
    data() {
        return {
            newBioName: ""
        };
    },
    methods: {
        nameKeyPressAction(event) {
            const restrictedChars = new RegExp("[.*\\W.*]");
            const newValue = this.newBioName + event.key;
            if (!restrictedChars.test(newValue))
                this.newBioName = newValue;
            return event.preventDefault();
        }
    }
    

    Edit:

    When you set a data property or a computed property as v-model of an input, vue associates them and yet, if user updates dom object via the input, property's setter is triggered and the process ends here. On the other hand, when you change the value of the property on javascript side, vue updates the dom object and this process also ends here.

    In your sample code, it seems like you expect that the computed property's getter to set the dom again but it can't. The property is already updated via dom change and it can't also update it. Otherwise, there might occur infinite loop.