Reputation: 590
I'm trying to make a custom input number
with + and - spin buttons to increment or decrement the current value
received via an http request
, if I type numbers directly on the input
it changes the value and when I save the content via form POST
it works, but if I execute element.stepUp/Down the value seems to change but the received value via POST
is the same as the original.
I was trying to trigger
an input event with this.$emit('input', newValue)
but it does not work because I can not specify the target to be altered. I tried to fire a custom event this.$emit('spin-button', value)
but the input is unable to listen to the emmited event with v-on:spin-button="myFunc()"
.
The v-model
cannot be a data variable
because is a dynamic form which contains more than 100 inputs
.
I only need to dispatch an input event when I click the spin buttons after i make the stepUp/Down to alter the value, but I'm not able to achieve it.
Is there a way to emit an event to a different or sibling element?
What is the correct way to do it and change the model value? I've tried with :value
but the result is the same.
const app = new Vue({
methods: {
showVal(data){
console.log(data)
}
},
incrementDecrementNumber(action, event) {
switch (action) {
case "+": {
event.target.parentElement.previousElementSibling.stepUp()
break;
}
case "-": {
event.target.parentElement.nextElementSibling.stepDown()
break;
}
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<div class="input-group mb-3 mx-auto col-md-6 border-dark" v-if="question.type.code === 'NI'">
<div class="input-group-prepend">
<button class="btn btn-circle" @click="incrementDecrementNumber('-', $event)">-</button>
</div>
<input
type="number"
class="form-control text-center form-control-lg"
@input="showVal($event)"
name="`test_1_question_5"
v-model.number="question.stored_data.answer"
/>
<div class="input-group-append">
<button class="btn btn-circle" @click="incrementDecrementNumber('+', $event)">+</button>
</div>
</div>
Upvotes: 1
Views: 6792
Reputation: 10334
You could create your own component to have better control over what's going on. That will also allow you to easily reuse it in other places.
Below is minimal example of how you can accomplish this, but can be expanded upon for better flexibility.
Vue.component('spin-button', {
template: '#spin-button',
props: {
'value': {
required: true
}
},
computed: {
internalValue: {
get() {
return this.value;
},
set(value) {
this.$emit('input', value)
}
}
},
methods: {
incrementDecrementNumber(action) {
switch (action) {
case "+":
this.$refs['input'].stepUp()
break;
case "-":
this.$refs['input'].stepDown()
break;
}
/* Need to manually $emit here since the above methods doesn't trigger our computed set method. */
this.$emit('input', this.$refs['input'].value)
}
}
})
new Vue({
el: "#app",
data() {
return {
question: {
stored_data: {
answer: 5
}
}
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<div id="app">
<spin-button v-model="question.stored_data.answer" step="5" min="0" max="100">
</spin-button>
{{ question.stored_data.answer }}
</div>
<template id="spin-button">
<div class="input-group">
<div class="input-group-prepend">
<button
class="btn"
@click="incrementDecrementNumber('-')"
>
-
</button>
</div>
<input type="number" ref="input" class="form-control text-center" v-model="internalValue" v-bind="$attrs" />
<div class="input-group-append">
<button class="btn" @click="incrementDecrementNumber('+')">
+
</button>
</div>
</div>
</template>
Upvotes: 2