Search code examples
vue.js

Change the bound v-model by changing the value in the input


I am trying to implement an on-screen keyboard for entering numbers into various input fields. In a real project, there are several dozen of them. I save the active field through focus and when I click on a number, it is added to the end of the field value. But when I change the value of the input, the value of the bound v-model does not change. Although, when I enter from a regular keyboard, everything changes normally. I am attaching the example code

<template>
    <p>xSize</p>
    <input v-model="xSize">
    <p>ySize</p>
    <input v-model="ySize">
    <div class="keyboard">
        <button v-for="i in [1,2,3,4,5,6,7,8,9,0]" class="key" :key="i" @click="addChar(i)">{{i}}</button>
    </div>
    <p>xSize = {{xSize}}</p>
    <p>ySize = {{ySize}}</p>
    <div class="test-box" v-bind:style="{width: this.xSize + 'px', height: this.ySize + 'px'}"></div>


</template>

<script>
export default {
  data: function () {
    return {
      xSize: 50,
      ySize: 50,
      activeElement: null
    }
  },
  props: {

  },
  created() {
    document.addEventListener('focusin', this.focusChanged)
  },
  beforeUnmount() {
    document.removeEventListener('focusin', this.focusChanged)
  },
  methods: {
    focusChanged: function (event) {
      const el = event.target
      if (el.type === "text") {
        if (this.activeElement !== el && this.activeElement !== null) {
          this.activeElement.style.background = "white";
        }

        this.activeElement = el
        this.activeElement.style.background = "red";
      }
    },
    addChar: function (char) {
      if (this.activeElement !== null) {
        this.activeElement.value += char
      }
    }

  }
}
</script>

<style scoped>
    .keyboard {
      display: flex;
    }
    .key {
      margin: 3px;
      width: 30px;
      height: 30px;
      border: 2px black ridge;
    }

    .test-box {
      border: 2px black ridge;
      background: red;
      margin: 15px;
    }
</style>

Example


Solution

  • Because what you modified was only the value of the element, not the responsive data in the data.

    You can change the code to this way.

    <template>
        <p>xSize</p>
        <input v-model="xSize" data-name="xSize">
        <p>ySize</p>
        <input v-model="ySize" data-name="ySize">
        <div class="keyboard">
            <button v-for="i in [1,2,3,4,5,6,7,8,9,0]" class="key" :key="i" @click="addChar(i)">{{i}}</button>
        </div>
        <p>xSize = {{xSize}}</p>
        <p>ySize = {{ySize}}</p>
        <div class="test-box" v-bind:style="{width: this.xSize + 'px', height: this.ySize + 'px'}"></div>
    
    
    </template>
    
    <script>
    export default {
      data: function () {
        return {
          xSize: 50,
          ySize: 50,
          activeElement: null
        }
      },
      props: {
    
      },
      created() {
        document.addEventListener('focusin', this.focusChanged)
      },
      beforeUnmount() {
        document.removeEventListener('focusin', this.focusChanged)
      },
      methods: {
        focusChanged: function (event) {
          const el = event.target
          if (el.type === "text") {
            if (this.activeElement !== el && this.activeElement !== null) {
              this.activeElement.style.background = "white";
            }
    
            this.activeElement = el
            this.activeElement.style.background = "red";
          }
        },
        addChar: function (char) {
          if (this.activeElement !== null) {
            const fieldName = this.activeElement.getAttribute("data-name");
            this[fieldName] += char
          }
        }
    
      }
    }
    </script>
    
    <style scoped>
        .keyboard {
          display: flex;
        }
        .key {
          margin: 3px;
          width: 30px;
          height: 30px;
          border: 2px black ridge;
        }
    
        .test-box {
          border: 2px black ridge;
          background: red;
          margin: 15px;
        }
    </style>