How to apply min/max attribute to v-model in Vue?
Solution 1
You could add a custom modifier to the v-model
directive:
// function that gets the min and max values for the element and prevents the value of the model from going below the min or above the max
function bindNumberInRange(el, binding, vnode) {
let model = binding.expression;
let min = parseInt(el.min);
let max = parseInt(el.max);
let val = parseInt(binding.value);
if ((min !== NaN) && (min >= val)) {
vnode.context[model] = min;
} else if ((max !== NaN) && (max <= val)) {
vnode.context[model] = max;
}
el.value = val;
}
// get the original reference to the v-model directive
let modelDirective = Vue.directive('model')
// set a new definition of the v-model directive
Vue.directive('model', {
bind: function(el, binding, vnode) {
// first fire the original v-model bind hook
modelDirective.bind(el, binding, vnode);
if (binding.modifiers.range) {
bindNumberInRange(el, binding, vnode)
}
},
componentUpdated: function(el, binding, vnode) {
// first fire the original v-model componentUpdated hook
modelDirective.componentUpdated(el, binding, vnode);
if (binding.modifiers.range) {
bindNumberInRange(el, binding, vnode)
}
}
})
Then, all you would need to do is add a .range
modifier to v-model
when you want the model to respect the min
and max
attributes of the affected element:
<input type="number" min="4" max="10" v-model.range="foo">
Here's a CodePen Example.
Here's Vue's (semi-lacking) documentation on directives.
Solution 2
Use @Focus to apply a max & min number validation to your :rules. Make sure to set the max with large default number. Both max & min default will be updated upon focusing on that specific input box. (This text-fields are being created with a loop)
<v-text-field type="number"
@focus="validateWhenFocused(item)"
:rules="numberRules"
:label="item.questionName"
v-model="item.value"
outline>
</v-text-field>
export default {
data() {
return {
numberRules: [
v => !!v || "Input is required!",
v =>
v < this.maxLength ||
`${this.errorName} must be less than ${this.maxLength} numbers`,
v =>
v > this.minLength ||
`${this.errorName} must be greater than ${this.minLength} numbers`
],
maxLength: 100,
minLength: 0,
errorName: "",
},
methods: {
validateWhenFocused(item){
this.maxLength = item.maxValue
this.minLength = item.minValue;
this.errorName = item.questionName
}
}
}
Édouard Lopez
Motivation I'm a quality-driven full-stack developer loving UX and devOps. Workflow include TDD and tests ; pair-programming ; code-review ; Trunk-based development ; Agile related. Languages and Tools Frontend: JS, ES6+, ReactJS, Vue.js, EmberJS, Angular, webpack/rollup ; test: unit Jest, AVA, end-to-end Cypress Backend: Python, Flask, Django, Unittest and Pytest ; DevOps: Docker/compose/Docker.py, Ansible ; Shell: bash/sh, fish, powershell test: Bats, fishtape, Pester Bonus I'm familiar with: UX (User eXperience) ; Accessibility ; Data-visualization ; IA (Information Architecture).
Updated on June 26, 2022Comments
-
Édouard Lopez almost 2 years
Current constraint of
min
andmax
are not respected due to the wayv-on
is implemented:<input id="passwordLength" class="form-control form-control-sm" type="number" min="5" max="35" v-model="options.length"> <span class="input-group-btn" v-on:click="options.length+=1"> <button class="btn btn-secondary" type="button"> <i class="fa fa-plus"></i> </button> </span>
Question
How can I respect the constrain and still keep an elegant implementation?