Vuejs keyup/ v-on:keyup event is not working - vue.js

I am trying to initiate a function from methods while an input is keyup, But it's not working. My codes from template are :
<q-input type="number" min="1" dense borderless debounce="300" class="q-ma-xs" v-
model="invoice_product.item_qty" placeholder="quantity" filled
#keyup="calculateLineTotal(invoice_product)" />
My method :
<script>
export default {
setup() {
return {
invoice_product: {
item_qty: ''
}
}
},
methods: {
calculateLineTotal(invoice_product) {
alert(invoice_product.item_qty)
}
}
}
</script>
I also tried with v-on:keyup

enter code hereYou can use watch property using your v model variable and there you can write your logic.
When your model value change it will called watch property
watch:{
“Variable” : function(val) {
//method
}
}

Try to replace setup with data:
new Vue({
el: '#q-app',
data() {
return {
invoice_product: {item_qty: ''}
}
},
methods: {
calculateLineTotal(invoice_product) {
alert(invoice_product.item_qty)
}
},
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/quasar#1.19.5/dist/quasar.min.css" rel="stylesheet" type="text/css">
<div id="q-app">
<q-input type="number" min="1" dense borderless debounce="300" class="q-ma-xs" v-
model="invoice_product.item_qty" placeholder="quantity" filled
#keyup="calculateLineTotal(invoice_product)" />
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#^2.0.0/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#1.19.5/dist/quasar.umd.min.js"></script>

Related

vuejs3 dynamic attribute with no value

How can I set up a dynamic attribute within vuejs3. Vanilla js is a lot easier, but within Vue this is apparently not obvious.
I want to be able to use a variable as an attribute.
Something like this:
<q-input
outlined <---(This must be variable "item.design" without any value)
v-model="data.value"
maxlength="12"
class="super-small subshadow-25"
/>
I've read some examples and documentation but the examples are mainly for vuejs2.
Do I miss something?
You can bind data vars to attributes just as easily using v-bind: on the attribute (or the shorthand :):
<q-input
:outlined="outlined"
:filled="filled"
v-model="data.value"
maxlength="12"
class="super-small subshadow-25"
/>
// script (options api)
data() {
return {
item: {
design: 'filled',
},
data: {
value: null,
},
};
},
computed: {
filled() {
return this.item.design === 'filled';
},
outlined() {
return this.item.design === 'outlined';
},
}
Take a look at following snippet you can pass true/false to binded attributes:
const { ref, computed } = Vue
const app = Vue.createApp({
setup () {
const data = ref({value: null})
const item = ref({design: 'filled'})
const design = (type) => {
return item.value.design === 'filled' ? 'outlined' : 'filled'
}
return { data, item, design }
}
})
app.use(Quasar)
app.mount('#q-app')
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/quasar#2.5.5/dist/quasar.prod.css" rel="stylesheet" type="text/css">
<div id="q-app">
<div class="q-pa-md">
<q-btn color="white" text-color="black" label="toogle design" #click="item.design = item.design === 'filled' ? 'outlined' : 'filled'" >
</q-btn>
<q-input
:filled="design(item.design)"
:outlined="design(item.design)"
v-model="data.value"
maxlength="12"
class="super-small subshadow-25"
/>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/quasar#2.5.5/dist/quasar.umd.prod.js"></script>

Vue Js - focusing on element programatically

I am brand new to using VueJs (first day!)
I want to validate an email field, and return focus to the email inut if not valid. I am using the watch property (see below), and although I can successfully watch value changes, I am not able to set focus back to the email field.
What am I doing wrong?
Code snippet
<!DOCTYPE html>
<head>
<title>V3 Example</title>
<script src="https://unpkg.com/vue#3"></script>
</head>
<style type="text/css">
form input, form button {
display: block;
margin: 3px;
}
</style>
<body>
<div id="app">
<form #submit.prevent >
<h3></h3>
<input type="username" v-model="username" />
<input ref="email" type="email" v-model="email" />
<input type="password" v-model="passwd" autocomplete="off"/>
<button #click="logIt" >Login </button>
</form>
</div>
<script>
let app = Vue.createApp({
data() {
return {
username: '',
email: '',
passwd: '',
}
},
methods: {
logIt() {
console.log('here!');
}
},
watch: {
email(val1, val2){
if (!val2.includes('#')) {
this.$refs.email.focus(); // <- this is supposed to return focus to email input
console.log('Not valid email!');
}
else {
console.log(val1);
console.log(val2);
}
}
}
})
app.mount('#app');
</script>
</body>
</html>
Try this:
this.$refs.email.$el.focus();
Here is a solution that works, I've added a method onSubmit which is called when the form submits and inside it I validate email field, and focus it if is not valid. The key here is nextTick which makes sure to wait before Vue does any DOM update it needs before focusing the element.
<!DOCTYPE html>
<head>
<title>V3 Example</title>
<script src="https://unpkg.com/vue#3"></script>
</head>
<style type="text/css">
form input, form button {
display: block;
margin: 3px;
}
</style>
<body>
<div id="app">
<form #submit.prevent="onSubmit" >
<h3></h3>
<input type="username" v-model="username" />
<input ref="email" type="email" v-model="email" />
<input type="password" v-model="passwd" autocomplete="off"/>
<button #click="logIt" >Login </button>
</form>
</div>
<script>
let app = Vue.createApp({
data() {
return {
username: '',
email: '',
passwd: '',
}
},
methods: {
logIt() {
console.log('here!');
},
onSubmit() {
if (!this.email.includes('#')) {
this.$nextTick(() => { // must wait for next tick before interacting with DOM
this.$refs.email.focus();
console.log('Not valid email!');
})
}
}
},
watch: {
email(val1, val2){
if (!val2.includes('#')) {
this.$refs.email.focus(); // <- this is supposed to return focus to email input
console.log('Not valid email!');
}
else {
console.log(val1);
console.log(val2);
}
}
}
})
app.mount('#app');
</script>
</body>

How initialize tabs when state changes in vue?

Here is sample of my code in vue.
<template>
<tabs>
<tab
v-for="c in myCount"
:key="c"
:name="c"
:selected="c === 1"
>
{{ c }}
</tab>
</tabs>
<button type="button" #click="showOneTab">Show just one tab</button>
</template>
<script>
export default {
name: 'myComponent',
data: {
return {
myCount: 5
}
},
methods: {
showOneTab() {
this.myCount = 1
}
}
}
</script>
myCount has default value of 5. after clicking a button it changes to 1. I need to tabs be removed and just the first appears.
Your code looks correct. But it doesn't work, you can try a computed property:
v-for="c in count"
computed: {
count() {
return myCount
}
}
Your data option should be a function that returns an object data(){ return { myCount: 5 } } not a field with object as value :
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data(){
return {
myCount: 5
}
},
methods: {
showOneTab() {
this.myCount = 1
}
}
})
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app" class="container">
<div v-for="c in myCount" :key="c">
{{ c }}
</div>
<button type="button" #click="showOneTab">Show just one tab</button>
</div>

Computed property setter creates Maximus stack exceeded

I have such code:
<div id="app">
<b-form-group label="Sorting">
<b-form-checkbox-group
v-model="sorting"
:options="filterData.sorting"
/>
</b-form-group>
</div>
new Vue({
el: '#app',
computed: {
sorting: {
get: function () {
return this.filterInput.sorting
},
set: function (value) {
// this array needs to always have only one value
this.filterInput.sorting = [value[0]]
}
}
},
data () {
return {
filterData: {
sorting: ['PRICE_ASC', 'PRICE_DESC']
},
filterInput: {
sorting: []
}
}
}
})
https://jsfiddle.net/pum86bsx/1/
Error seems to be in computed getter. When I comment it out it's all good. I have no idea why it's like that.
You setting the value of the v-model (the value returned in the getter), which will cause the setter to fire again.. and again.. and again.. Causing your stack to overflow.
Using checkboxes
You could instead use the #change event, which should only fire when the value actually changes.
new Vue({
el: '#app',
data () {
return {
filterData: {
sorting: ['PRICE_ASC', 'PRICE_DESC']
},
filterInput: {
sorting: []
}
}
},
methods: {
onChange(value) {
if(value.length === 0) {
this.filterInput.sorting = value
} else {
this.filterInput.sorting = [value[value.length - 1]]
}
}
}
})
<link href="https://unpkg.com/bootstrap#4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.15.0/dist/bootstrap-vue.js"></script>
<div id="app">
<b-form-group label="Sorting">
<b-form-checkbox-group
v-model="filterInput.sorting"
:options="filterData.sorting"
#change="onChange"
></b-form-checkbox-group>
</b-form-group>
</div>
Using radio buttons
Alternatively you could use radio buttons, which only allows one to be selected at a time, so you don't have to handle that yourself.
new Vue({
el: '#app',
data () {
return {
filterData: {
sorting: ['PRICE_ASC', 'PRICE_DESC']
},
filterInput: {
sorting: []
}
}
}
})
<link href="https://unpkg.com/bootstrap#4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.15.0/dist/bootstrap-vue.js"></script>
<div id="app">
<b-form-group label="Sorting">
<b-form-radio-group
v-model="filterInput.sorting"
:options="filterData.sorting"
></b-form-radio-group>
</b-form-group>
</div>

Vuelidate reset specific field so that $error flag is false

Using Vuelidate you can reset the validation errors by using this.$v.$reset(). In this Codepen example resetting the lastName field that uses a Vuetify component works - $invalid is true while $error is set to false.
When resetting the regular text input for firstName it doesn't work as the $error flag is still true. How can I modify the text input so that $error is false when calling reset?
I've also tried this.$nextTick(() => {...}) but that doesn't work either.
Vue.use(window.vuelidate.default)
var validationMixin = window.vuelidate.validationMixin
const {
maxLength,
required
} = window.validators
new Vue({
el: '#app',
mixins: [validationMixin],
data: () => ({
form: {
firstName: '',
lastName: ''
}
}),
validations: {
form: {
firstName: {
required, maxLength: maxLength(2)
},
lastName: {
required, maxLength: maxLength(2)
},
}
}
})
input.raw {
border: solid;
}
.is-invalid {
border-color: #FF5252 !important;
}
<html>
<head>
<script src="https://unpkg.com/vuelidate#0.6.1/dist/validators.min.js"></script>
<script src="https://unpkg.com/vuelidate#0.6.1/dist/vuelidate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
</head>
<body>
<div id="app">
<label for="firstName">First Name</label>
<input
v-model="form.firstName"
id="firstName"
class="raw"
:class="{ 'is-invalid': $v.form.firstName.$error }"
type="text"
width="100%"
:oninput="$v.form.firstName.$touch()"
:onblur="$v.form.firstName.$touch()"
/>
<button #click="$v.form.firstName.$touch()">
$touch
</button>
<button #click="$v.form.firstName.$reset()">
$reset
</button>
<pre>{{ $v.form.firstName }}</pre>
</div>
</body>
</html>
In your example, you are using oninput and onblur HTML attributes, but in Vue, you should use #input(v-on:input) and #blur(v-on:blur) bindings instead. See docs for details.
Replacing HTML attributes with Vue bindings made your example work correctly:
Vue.use(window.vuelidate.default)
var validationMixin = window.vuelidate.validationMixin
const {
maxLength,
required
} = window.validators
new Vue({
el: '#app',
mixins: [validationMixin],
data: () => ({
form: {
firstName: '',
lastName: ''
}
}),
validations: {
form: {
firstName: {
required, maxLength: maxLength(2)
},
lastName: {
required, maxLength: maxLength(2)
},
}
}
})
input.raw {
border: solid;
}
.is-invalid {
border-color: #FF5252 !important;
}
<html>
<head>
<script src="https://unpkg.com/vuelidate#0.6.1/dist/validators.min.js"></script>
<script src="https://unpkg.com/vuelidate#0.6.1/dist/vuelidate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
</head>
<body>
<div id="app">
<label for="firstName">First Name</label>
<input
v-model="form.firstName"
id="firstName"
class="raw"
:class="{ 'is-invalid': $v.form.firstName.$error }"
type="text"
width="100%"
#input="$v.form.firstName.$touch()"
#blur="$v.form.firstName.$touch()"
/>
<button #click="$v.form.firstName.$touch()">
$touch
</button>
<button #click="$v.form.firstName.$reset()">
$reset
</button>
<pre>{{ $v.form.firstName }}</pre>
</div>
</body>
</html>
This is Issue From Vuelidate and they must be fixed, in this position you can not reset form and give same (badly) behavior you can re-render by the router
// re render component for reset all fileds
this.$router.go(0)