Numeric fields with increment / decrement buttons
Create numeric input fields with custom buttons using QInput and QBtn or change value by dragging.
Create numeric input fields with custom buttons using QInput and QBtn or change value by dragging.
You need to create numeric form field with buttons to increase / decrease the value.
Use a base QInput and use the #before
, #prepend
#append
, or #after
slots to place the buttons.
Use vTouchRepeat
to change value as long as a button is pressed.
Use vTouchPan
to change the value by dragging.
<template>
<div class="col column no-wrap">
<div class="q-pa-md column q-gutter-y-md" style="max-width: 400px">
<q-input
style="max-width: 200px"
v-model.number="model"
type="number"
:step="1"
standout
dense
color="primary"
input-class="text-right q-no-input-spinner"
>
<template v-slot:prepend>
<q-btn
style="margin-left: -12px; border-top-right-radius: 0; border-bottom-right-radius: 0"
unelevated
color="red-6"
icon="remove"
padding="sm"
v-touch-repeat:0:500:100.mouse.enter.space="decrement"
/>
</template>
<template v-slot:append>
<q-btn
style="margin-right: -12px; border-top-left-radius: 0; border-bottom-left-radius: 0"
unelevated
color="green-6"
icon="add"
padding="sm"
v-touch-repeat:0:500:100.mouse.enter.space="increment"
/>
</template>
</q-input>
<q-input
style="max-width: 200px"
v-model.number="model"
type="number"
:step="1"
outlined
dense
color="primary"
input-class="text-right q-no-input-spinner"
>
<template v-slot:prepend>
<q-icon
style="cursor: ns-resize"
name="swap_vert"
v-touch-pan.vertical.mouse.prevent="onPan"
/>
</template>
<template v-slot:append>
<q-btn
flat
color="primary"
icon="remove_circle_outline"
padding="7px"
v-touch-repeat:0:500:100.mouse.enter.space="decrement"
/>
<q-btn
style="margin-right: -11px"
flat
color="primary"
icon="add_circle_outline"
padding="7px"
v-touch-repeat:0:500:100.mouse.enter.space="increment"
/>
</template>
</q-input>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const model = ref(0);
let onPanTimer = null;
let onPanValue = 0;
function increment() {
model.value += 1;
}
function decrement() {
model.value -= 1;
}
function onPan({ offset, isFirst, isFinal }) {
const sign = Math.sign(-offset.y);
const dist = Math.max(0, Math.abs(offset.y) - 5);
const newPanValue = sign * Math.ceil(dist / 20);
if (onPanTimer !== null) {
clearInterval(onPanTimer);
}
if (isFinal !== true && newPanValue !== 0) {
if (newPanValue !== onPanValue) {
onPanValue = newPanValue;
model.value += onPanValue;
}
onPanTimer = setInterval(() => {
model.value += onPanValue;
}, Math.max(20, 1000 / dist));
} else {
onPanTimer = null;
}
}
</script>