Is there anyway to set a different value for the "input" than the vue variable? - vue.js

I need to change the display of a input depending on the value returned from the db for this variable: paragraph.RCBulletinNumber
I have tried the computed method, but I think this is not what I need
computed: {
formatRCBulletinNumber: {
set (val){
return this.paragraph.RCBulletinNumber;
}
}
},
This is my input declaration using v-model='paragraph.RCBulletinNumber':
<div class="form-group">
<div v-if='typeof paragraph != undefined /*/<!--&& parseInt(paragraph.RCBulletinNumber)>0 -->/*/'>
<input type="text" style="width: 40%;" class='form-control' id="RCNumber" placeholder="RC Number" v-model='paragraph.RCBulletinNumber'>
</div>
</div>
What I expect is that if the value of paragraph.RCBulletinNumber is less than or equal to 0 the input remains empty. Right now if the variable equals 0 the input is 0
But if the paragraph.RCBulletinNumber is equal to 0, the value must go to the database again, my goal is just to change the value of the input to be more userfriendly.

Simply define the getter and setter of the computed property:
computed: {
formatRCBulletinNumber: {
// getter
get: function () {
return this.paragraph.RCBulletinNumber || '';
},
// setter
set: function (newValue) {
this.paragraph.RCBulletinNumber = newValue;
}
}
}
And then reference the computed property on the input:
<input type="text" style="width: 40%;" class='form-control' id="RCNumber" placeholder="RC Number" v-model='formatRCBulletinNumber'>
reference: https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter

Related

change data variable when passed into a method in vue

I have the following vue component where I am changing the class of the parent row based on whether or not an input is focused
<template>
<div class="form form--login">
<div class="form__row" :class="{entered: emailEntered}">
<label class="form__label" for="login-form-email">Email address</label>
<input type="text" class="form__control form__control--textbox" name="email-address" id="login-form-email" #focus="emailEntered = true" #blur="handleBlur($event, emailEntered)">
</div>
<div class="form__row" :class="{entered: passwordEntered}">
<label class="form__label" for="login-form-password">Password</label>
<input type="password" class="form__control form__control--textbox form__control--password" name="password" id="login-form-password" #focus="passwordEntered = true" #blur="handleBlur($event, passwordEntered)">
</div>
</div>
</template>
<script>
export default {
name: 'login-form',
data() {
return {
emailEntered: false,
passwordEntered: false,
}
},
methods: {
handleBlur(e, enteredBool) {
if (e.currentTarget.value.trim() === '') {
// this doesn't do anything - I can do an if else statement to change this.passwordEntered or this.emailEntered based on the name of the current target, but how do I change the value by passing it into the method?
enteredBool = false;
}
},
}
}
</script>
but it doesn't seem to change the variable that is passed into the method - how do I pass a data variable into the method and change it's value? Or should I be doing it in a different way? I don't really want to be doing an if else statement as I may have a form that has got a lot more inputs on and I think that would be really inefficient to maintain
I also thought that I could do something in the #bur as you can do #blur="passwordEntered = false", but I wasn't sure how to check if the field was empty or not
In order to change the variable, you need to refer it using this
handleBlur(e, enteredBool) {
if (e.currentTarget.value.trim() === '') {
this[enteredBool] = false; //Change added
}
},
and the way you pass it should be like
#blur="handleBlur($event, 'emailEntered')" //Added single quotes
and
#blur="handleBlur($event, 'passwordEntered')" //Added single quotes

Value of input not changed

Using Vue3 and Vuex4
I got an input field:
<input :class="invalid.includes(item.attribute) ? 'invalidInput' : 'validInput'" type="text" :id="item.attribute" :name="item.attribute" :placeholder="item.default_value" min="0" step="any" :value="item.value" #input="validate(item.attribute, $event)" class="p-1">
I change the value of "invalid" like this. Just checking for the validity of a regex and adding/removing the attribute to the array.
VALIDATE_INPUT: (state, data) => {
var regex = /(?=.*\d)^\$?(([1-9]\d{0,2}(,\d{3})*)|0)?(\.\d{1,2})?$/;
switch (data.attribute) {
case 'invoice_amount_f':
if (!regex.test(data.value)) {
state.validations.push(data.attribute)
} else {
let index = state.validations.findIndex(el => el === data.attribute);
if (index > -1) {
state.validations.splice(index, 1);
}
}
break;
default:
break;
}
}
The action calling the mutation is called like:
const validate = (attribute, event) => {
store.dispatch('validate', {
attribute: attribute,
value: event.target.value
});
}
Computed:
var invalid = computed({
get() {
return store.getters.getValidationState;
}
});
When now typing something into the input field the text in the field ain't chaning. This seems to happen cause I use the value of invalid inside the template. Why is that?
EDIT: It seems to have something to do with the scope I am using it in.
<h3>{{ invalid }}</h3>
<div v-if="nestedListItems && Object.keys(nestedListItems).length !== 0">
<draggable v-model='nestedListItems' item-key="id" class=" w-12/12 bg-white m-auto border" animation="150">
When rendering it outside of draggable it's absolutely fine. Inside it crashes my store.
You need to provide an object to the :class, see here:
https://v3.vuejs.org/guide/class-and-style.html#binding-html-classes
I suggest you create a variable in the script containing the boolean e.g. isValid and then apply it like this:
:class="{invalidInput : !isValid, validInput: isValid }"

Returned Value From Computed Property Doesn't Change When It's Used In Template (Vue3 without Composition API)

I'm trying to get an item's width in a computed property to pass it to CSS variable.
<div class="wrapper">
<fieldset>
<legend :style="`--gap:${legendGap}px`"></legend>
</fieldset>
<label>{{ label }}</label>
<input/>
</div>
computed: {
legendGap() {
if (
!this.$el ||
this.label == '' ||
!this.design == 'outlined' ||
!this.options.some((x) => ['has-placeholder', 'is-dirty', 'is-focused'].includes(x))
) {
return 0;
}
return (
parseFloat(
window.getComputedStyle(this.$el.querySelector('label')).getPropertyValue('width')
) * 0.8
);
}
If I remove :style="`--gap:${legendGap}px`" from template or change the variable name, computed property returns correct value, otherwise it returns 0. So somehow, using the computed property in the template locks its value. I haven't seen anything like that before. I assume that using $el causes the problem, but I'm not sure.
How can I make the computed property returns the correct value without removing the variable from template?
UPDATED, sorry I fixed a few script errors, I think it should be good now, let me know if you still have issues.
=========
Maybe try a different approach like this, I just hand coded it, you may double check for typos etc.
<div class="wrapper">
<fieldset>
<legend :style="`--gap:${legendGap}px`"></legend>
</fieldset>
<label ref="label">{{ label }}</label>
<input/>
</div>
data() {
return {
legendGap: 0
}
},
watch: {
label() {
this.calcLegendGap()
}
},
mounted() {
// needed to set the init value after all rendered
this.calcLegendGap()
},
methods: {
calcLegendGap() {
if (
!this.label ||
this.design !== 'outlined' ||
!this.options.some((x) => ['has-placeholder', 'is-dirty', 'is-focused'].includes(x))
) {
this.legendGap = 0;
} else {
// $nextTick is required we need to wait for DOM update
this.$nextTick(() => {
this.legendGap = parseFloat(
window.getComputedStyle(this.$refs.label).getPropertyValue('width')
) * 0.8;
});
}
}
}

v-text-field returns string after typing even though it has type number

<VTextField
:value="addOnStartingPrice"
solo
outline
reverse
append-icon="attach_money"
type="number"
min="0"
step="any"
#input="$emit('update:addOnStartingPrice', $event)"
/>
I have something like this.
Question 1) as soon as i change the number or type in it, it throws number value correctly, but its type is String instead of number, so type check gets failed. How do I get it to return value as type:number?
Question 2) what exactly does step="any" and min="0" do? They don't work I guess, because i can type negative numbers too.
Indeed vuetify returns string. As a workaround you can use number modifier.
<v-text-field type="number" v-model.number="computedAddOnStartingPrice" />
And you can have a computed property like this:
computed: {
computedAddOnStartingPrice: {
get () { return this.addOnStartingPrice },
set (newVal) { this.$emit('update:addOnStartingPrice', newVal) }
}
}
As per the step attribute read Html input step.
And for min attr read Html input min
You can also use vuetify rules to check if the user has entered a positive number. Example:
<v-text-field
type="number"
step="any"
min="0"
:rules="[numberRule]"
v-model.number="computedAddOnStartingPrice"
></v-text-field>
The numberRule:
data: () => ({
//...
numberRule: val => {
if(val < 0) return 'Please enter a positive number'
return true
}
})
See it in action
The issue lies here as the value property of InputElements is string.
And it gets casted when needed
One thing you can do is "fix" by extend/override:
import * as comps from "vuetify/es5/components";
...
const override = comps.VTextField.extend({
onInput(e) {
const target = e.target;
if (this.type !== "number") this.internalValue = target.value;
else {
this.internalValue = target.valueAsNumber;
}
this.badInput = target.validity && target.validity.badInput;
}
});
Vue.component('NewVTextField, override);
Or "workaround" by $emit(+$event), as this seems to be the intended path
But i guess you should use the setter, getter aproach - as you can also chain validators in the setter
check: #roli loli:
computed: {
computedAddOnStartingPrice: {
get () { return this.addOnStartingPrice },
set (newVal) { this.$emit('update:addOnStartingPrice', newVal) }
}
}
Just convert in to Number in #input handler.
<VTextField
:value="addOnStartingPrice"
solo
outline
reverse
append-icon="attach_money"
type="number"
min="0"
step="any"
#input="$emit('update:addOnStartingPrice', Number($event))"
/>
<input v-model.number="price" type="number">
data() {
return {
price: '',
}
},
will save integer
I was able to use v-on:change Event to convert my input. I wasn't able to get
Andrew Vasilchuk's answer to work.
<v-text-field
v-model="item.quantity"
label="Quantity"
type="number"
v-on:change="item.quantity = parseFloat(item.quantity)"
></v-text-field>

Vue computed setter not working with checkboxes?

I have a computed setter:
rating: {
get() {
return this.$store.state.rating;
},
set(value) {
console.log(value);
this.$store.commit('updateFilter', {
name: this.name,
value
});
}
}
This is linked to my rating like so:
<label>
<input type="checkbox" :value="Number(value)" v-model="rating">
{{ index }}
</label>
I expect the computed setter to log an array because when I use a watcher to watch for changes on the rating model I am getting an array.
Except whenever I use a computed setter like above it simply outputs true when a checkbox is selected or false when they are all deselected.
What is going on here, should I just be getting an array just as like with a watcher?
v-model has somewhat "magical" behavior, particularly when applied to checkboxes. When bound to an array, the checkbox will add or remove the value to/from the array based on its checked state.
It is not clear in your example what value is in Number(value). It should be a value that you want included in the array when the box is checked.
Taking the example from the Vue docs linked above, I have modified it to use a computed, and it works as you might expect, with the set getting the new value of the array.
new Vue({
el: '#app',
data: {
checkedNames: []
},
computed: {
proxyCheckedNames: {
get() {
return this.checkedNames;
},
set(newValue) {
this.checkedNames = newValue;
}
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
<input type="checkbox" id="jack" value="Jack" v-model="proxyCheckedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="proxyCheckedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="proxyCheckedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>