Subscribe on changes!

Validating/Modifying new input before writing it to varaible from v-model

avatar
Mar 28th 2023

What problem does this feature solve?

Before I say anything this might be that I am not skilled enough in vue an there is a way to do this already.

Context:

The issue I'm having is that I have a variable price (reactive object) { min: 0, max: 0 } I have two range inputs that each modify those values. Then I have two normal number inputs that display the value and allow user to modify them if the desired value is too hard to get right with just the slider. The there is a maximum price (set by the most expensive product) and minimum price (defalult 0)

template:

<input type="number" v-model="price.max">
<input type="number" v-model="price.min">

<input type="range" min="0" max="maximum" v-model="price.max">
<input type="range" min="0" max="maximum" v-model="price.min">

script setup:

const maximum = 1000;

const price = reactive({
  min: 0,
  max: 1000
});

The problem:

First thing that I had coded was only the sliders so the user was limited by the sliders max and min properties from html But right now when I added the number inputs the user is not limited to anything and everything breaks when they enter too large number.

The solution:

In vue we already have modifications of v-model like v-model.number="targetVar" What I would like to see is this type of thing but user defined something like v-model.validate(functionFromScript)="targetVar" This would call the function from script which would return either true or false and that will decide if the value is going to get changed or not. This could also introduce another thing like v-model.modify(frunctionFromScript)="targetVar" What this would do is that the value would get processed and modified by user defined function. It would work the same as v-model.number="targetVar" because what I assume is that .number calls the Number() constructor on the input before passing it down the code.

Conclusion:

I know there is a way to kinda do this with writable computed but from what I heard writable computed is not a good thing to use and it cannot be used as cleanly and isn't as reusable as this solution. This solution could also allow the user to stack the functions and reuse them.

This feature would be used every time you want to protect your raw data in script because you cannot assume that user would enter only valid input. Some browsers even ignore the input type for example I think that firefox allows the user to enter characters into number inputs

What does the proposed API look like?

<template>

<input type=number v-model.number.validate(rangeValidation)="validatedNumber">

</template>

<script setup>
const max = 1000;
const min = 0;

const validatedNumber = ref(0);

function rangeValidation(input) {
  if (input > max) return false;
  if (input < min) return false;
  // More test cases
  return false;
}

</script>
avatar
Mar 28th 2023

It seems that you want to be able to define a verification function when the v-model is updated. If the data verification fails, it will not be updated. In my opinion, v-model on the native dom does not seem to have this ability, you can do a high-level component package to achieve your needs (https://vuejs.org/guide/components/v-model.html# handling-v-model-modifiers), in vueuse, the v-model of the component can be verified before emit (https://github.com/vueuse/vueuse/pull/2836)

avatar
Mar 28th 2023

That's why is it a feature request, I think you could say that you can use high level stuff about everything. The thing is (as I pointed out in the request) that vue already almost has this functionality just doesn't allow to make user defined modifiers. And I want to be able to use this without having to use components because I don't want to emit the value because it would be useless unless I was already doing it.

avatar
Apr 19th 2023

You could add a listener for value changes in your input, that would call the validate function and update your data. Then you could bind your input to your variable. Basically skip v-model (two way binding) and use v-bind (one way bind) instead, with a listener.

avatar
Apr 19th 2023

@tho-daskalakis That would get messy with multiple validators or modifiers. I'm not looking for alternative ways to do this. You could say we don't need router as we could do v-if on every page and then have a variable which determined on which page are we. I'm requesting it because it already is in vue it just cannot be made custom.

avatar
Apr 19th 2023

You should be having different validators for different inputs anyways. In your requested feature, you would be using multiple validators as well. The example you mentioned with vue-router vs v-if is not accurate, as in vue-router you have extra functionality, like lazy loading.

If you are concerned about a component becoming too complex and bloated, why not break it up to different input components, each one with their own validators? I see this would be a different way of writing a single directive v-model.validate.validateValue="value" instead of two different ones :value="value" @input="validateValue", but the functionality is already there, and the proposed feature doesn't seem to reduce complexity imo.

avatar
Apr 19th 2023

First of all how do you want to break up one input into multiple ones that's my first question. And right now this would make it more readable. Right now if you would like to chain those validation methods you would have to make functions that call each other and the last would change the value. With my solution you would just define function that would return either true or false depending if the input passed the validation, or modify the value if it is a modifier not validator. This would introduce opportunity for libraries with validating functions that you could just import and use in the template.