Subscribe on changes!

Input field is not reactive updating as expected

avatar
Apr 19th 2023

Vue version

3.3.0-alpha.12

Link to minimal reproduction

Vue SFC Playground

Steps to reproduce

Works with different maximum numbers:

Default Example Case with max value 100

Type a number into the input field

If the number is starting with a "1" and you type afterwards 2 digits like "04". Then the displayed value in the Input field is updated to be the max value 100 which is expected.

If you add a 4th digit like 1000 suddenly the computed getter is not called anymore. The emitted value by the NumberInput Component is still correct. But the displayed number in the input is wrong.

For all numbers between 100 and 199 it works as expected If you habe the number 100 and alter the first digit than even 200 it doesn't work properly If you type 200 into an empty input it works

Using the add and subtract buttons always works

Case max 1000

Behaves similar. Only works as expected for number from 1000 1999

What is expected?

All numbers that are entered above the max value should be "clamped" to the max value and should be also displayed like that in the input field

What is actually happening?

Number which are entered above the max value are getting correct clamped in the "ref" variable. But the input field is not updating correctly.

System Info

System:
    OS: macOS 13.3.1
    CPU: (8) arm64 Apple M1
    Memory: 160.80 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 16.20.0 - /opt/homebrew/opt/node@16/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 8.19.4 - /opt/homebrew/opt/node@16/bin/npm
  Browsers:
    Chrome: 112.0.5615.121
    Firefox: 112.0.1
    Safari: 16.4
  npmPackages:
    vue: ^3.2.37 => 3.2.47 // but also in 3.3.0-alpha.12 of the SFC Playground

Any additional comments?

No response

avatar
Apr 19th 2023

This is kinda expected because after 100 has been set for the first time, for any new input above 100,

  1. the NumberInput emits the same value each time: 100.
  2. So the parent never needs to re-render,
  3. and as result never passes a new modelValuevalue to the child,
  4. so the NumberValue never re-renders and
  5. without a re-render, the inout value is never updated back to 100.

the v-model on the input syncs the input to the local ref. if that ref never changes, Vue sees no need to update the input.

clamping the value in this way does not work with v-model, because it wants to keep the values in sync, but you break that synchronisation.

You would need to use a template ref and manually re-set the input value whenever the clamp function resets a value to the max/min.

  const inputField = ref()

// create clamp function
function clamp(value: number, min: number, max: number): number {
    const newValue = Math.min(Math.max(value, min), max);
    if (newValue !== value) {
      inputField.value.value = newValue
    }
    return newValue
}