Reputation: 2000
I am using this package from GitHub for minus plus input for Vue.js. In the example
folder, there is a sample file named plusminusfield.vue
. This is the component's data:
export default {
props: {
value: {
default: 0,
type: Number,
},
base_capacity: {
type: Number,
required: true,
},
min: {
/**
* Here I want to use a variable named `base_capacity`,
* which is passed as a prop above. If I hardcode a value here,
* like 5, for example, it works, but this is not what I want.
*/
default: 5,
type: Number,
},
max: {
default: 22,
type: Number,
},
},
data() {
return {
newValue: this.base_capacity,
};
},
// ...
};
Here are some methods for validating the input value, and a watcher for changing it:
export default {
// ...
methods: {
getNotificationClass(notification) {
return `alert alert-${notification.type}`;
},
mpminus: function () {
if (this.newValue > this.min) {
this.newValue = this.newValue - 1;
this.$emit("input", this.newValue);
}
},
mpplus: function () {
if (this.max === undefined || this.newValue < this.max) {
this.newValue = this.newValue + 1;
this.$emit("input", this.newValue);
}
},
},
watch: {
value: {
handler: function (newVal, oldVal) {
this.newValue = newVal;
},
},
},
// ...
};
If I define newValue
somewhere else, and use it in the props, I get an error saying that props can't be mutated, and my app doesn't run. And if I make the minimum of the input a computed property, like below, the error mentioned in the comments pops up:
export default {
computed: {
// Maximum call stack size exceeded
min() {
return this.min ? this.min : this.base_capacity;
},
// `base_capacity` is undefined
min: this.base_capacity,
},
};
Is there any other way to pass the min value to that input?
Upvotes: 13
Views: 11925
Reputation: 394
While the accepted answer will work for Vue 2.x, in Vue 3.x prop default factory functions no longer have access to this
. Instead you can pass the component's props as an argument to the factory function:
props: {
...
baseCapacity: {
default: 0,
type: Number
},
min: {
default: (props) => props.baseCapacity,
type: Number
},
...
},
See the migration guide: https://v3-migration.vuejs.org/breaking-changes/props-default-this.html
Upvotes: 26
Reputation: 3520
Instead of using it directly, use a factory function and return the value.
moreover, HTML attributes are case-sensitive.
Example: If you set the attribute as: base-capacity
, Vue will automatically convert it into the camel-case as baseCapacity
to access it from the script.
Here is the official docs
Vue.component('plus-minus', {
template: '#vplusminus',
props: {
value: {
default: 0,
type: Number
},
baseCapacity: {
default: 0,
type: Number
},
min: {
default: function () {
return this.baseCapacity
},
type: Number
},
max: {
default: undefined,
type: Number
}
},
data() {
return {
newValue: 0
}
},
methods: {
getNotificationClass(notification) {
return `alert alert-${notification.type}`
},
mpplus: function() {
if (this.max === undefined || (this.newValue < this.max)) {
this.newValue = this.newValue + 1
this.$emit('input', this.newValue)
}
},
mpminus: function() {
console.log(this.min); // Here it is coming as 12
if ((this.newValue) > this.min) {
this.newValue = this.newValue - 1
this.$emit('input', this.newValue)
}
}
},
watch: {
value: {
handler: function(newVal, oldVal) {
this.newValue = newVal
}
}
},
created: function() {
this.newValue = this.value
}
});
new Vue({
el: '#app'
});
.minusplusnumber {
border: 1px solid silver;
border-radius: 5px;
background-color: #FFF;
margin: 0 5px 0 5px;
display: inline-block;
user-select: none;
}
.minusplusnumber div {
display: inline-block;
}
.minusplusnumber #field_container input {
width: 50px;
text-align: center;
font-size: 15px;
padding: 3px;
border: none;
}
.minusplusnumber .mpbtn {
padding: 3px 10px 3px 10px;
cursor: pointer;
border-radius: 5px;
}
.minusplusnumber .mpbtn:hover {
background-color: #DDD;
}
.minusplusnumber .mpbtn:active {
background-color: #c5c5c5;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<plus-minus :base-capacity="12" :value="16"></plus-minus>
<plus-minus></plus-minus>
</div>
<script type="template/text" id="vplusminus">
<div class="minusplusnumber">
<div class="mpbtn minus" v-on:click="mpminus()">
-
</div>
<div id="field_container">
<input type="number" v-model="newValue" disabled />
</div>
<div class="mpbtn plus" v-on:click="mpplus()">
+
</div>
</div>
</script>
Upvotes: 10
Reputation: 14201
You shouldn't use another prop
as the default value. Even if they are available you have no guarantee regarding the order in which the props are evaluated.
A better approach is to use a computed property that takes into account both props and use that one inside your component.
computed: {
minComputed () {
return this.min ? this.min : this.base_capacity
}
}
Also, remove the default
value from the definition of min
Upvotes: 3