I'm trying to figure out how to validate inputs immediately after adding them:
template:
<div id="app">
<div
v-for="(message, index) in messages"
:key="index"
>
<v-text-field
v-model="messages[index]"
:rules="[v => !!v || 'Error: Please enter text']"
/>
</div>
<v-btn #click="add()">Add input</v-btn>
</div>
JS:
new Vue({
el: '#app',
data: {
messages: ['Hi', 'Hello'],
},
methods: {
add(val) {
this.messages.push(val);
},
},
});
Codepen: https://codepen.io/Zurab-D/pen/dymGaRY
What I mean is that when the button is clicked, a new input appears and there is no "Error: Please enter text" error message by default.
Can I make this message appear immediately?
You can put your template's code, where you use v-for directive, between v-form tags:
<v-form ref="form">
<div v-for="(message, index) in messages" :key="index">
<v-text-field v-model="messages[index]"
:rules="[v => !!v || 'Error: Please enter text']" />
</div>
<v-btn #click="add()">Add input</v-btn>
</v-form>
and then inside add() method validate form by using built-in validate() function in v-form reference
async add(val) {
this.messages.push(val);
await this.$nextTick(); // wait until a new text-field will be rendered
this.$refs.form.validate(); //validate form
},
An example on CodePen is here
To achieve this you can use this.$refs.form.validate(). Wrap your inputs inside <v-form> tag and add an attribute ref="form".
Live Demo :
new Vue({
vuetify: new Vuetify(),
data: {
messages: ['Hi', 'Hello']
},
methods: {
required: value => !!value || 'Please enter text',
add(val) {
this.messages.push(val);
setTimeout(() => {
this.$refs.form.validate();
})
}
}
}).$mount('#app')
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css"/>
<div id="app">
<v-app>
<v-form ref="form">
<div v-for="(message, index) in messages" :key="index">
<v-text-field v-model="messages[index]" :rules="[required]"/>
</div>
<v-btn #click="add()">Add input</v-btn>
</v-form>
</v-app>
</div>
Related
i have this v-select whose items charge dinamicaly, the user can choose several options from it, the problem is i have to many options and i want the user can search the option that he/she wants writing text:
<v-col cols="7">
<v-select
v-model="fillModReparacion.listamanodeObraC"
:items="fillModReparacion.listamanodeObra"
item-value="itg_id"
item-text="itg_descripcion"
attach
chips
label="Mano de Obra"
multiple
outlined
clearable
return-object
></v-select>
</v-col>
You can use v-slot:prepend-item to prepend the search before the options list inside v-select.
Live Demo :
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: () => ({
searchTerm: "",
fruits: [
"Apples",
"Apricots",
"Avocado",
"Bananas",
"Blueberries",
"Blackberries",
"Dates",
"Eggplant",
"Figs",
"Grapes",
"Grapefruit",
"Guava"
],
fruitsCopy: [],
selectedFruits: []
}),
mounted() {
this.fruitsCopy = [...this.fruits];
},
computed: {},
methods: {
searchFruits(e) {
if (!this.searchTerm) {
this.fruits = this.fruitsCopy;
}
this.fruits = this.fruitsCopy.filter((fruit) => {
return fruit.toLowerCase().indexOf(this.searchTerm.toLowerCase()) > -1;
});
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.2.21/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify#2.2.21/dist/vuetify.min.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css"/>
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-select v-model="selectedFruits" :items="fruits" attach label="Favorite Fruits" multiple>
<template v-slot:prepend-item>
<v-list-item>
<v-list-item-content>
<v-text-field v-model="searchTerm" placeholder="Search" #input="searchFruits"></v-text-field>
</v-list-item-content>
</v-list-item>
<v-divider class="mt-2"></v-divider>
</template>
</v-select>
</v-container>
</v-app>
</div>
When a new account is registered, I display login and password details on the screen. The user can copy login&passwod details to clipboard and I would like to run animation when the append-icon (scale up, increase font or replace with another icon) is clicked. What would be the right way to do that?
<template>
<v-card class="col-12 col-md-8 col-lg-6 p-6 px-16" elevation="4">
<div class="title h2 mb-10 text-uppercase text-center">
Success
<v-icon color="green" x-large>
mdi-check-circle
</v-icon>
</div>
<v-text-field
:value="newAccount.login"
label="Login"
outlined
readonly
append-icon="mdi-content-copy"
ref='login'
#click:append="copy('login')"
></v-text-field>
<v-text-field
:value="newAccount.password"
label="Password"
outlined
readonly
append-icon="mdi-content-copy"
ref='login'
#click:append="copy('login')"
></v-text-field>
</v-card>
</template>
<script>
methods: {
copy(field) {
const input = this.$refs[field].$refs.input
input.select()
document.execCommand('copy')
input.setSelectionRange(0,0)
// apply append-icon animation
}
}
</script>
There is multiple answers to this, but to answer one of them: "replacing icon" would be pretty straight forward.
You would have to change the append-icon prop do be dynamic :, then assign a variable to it like copyIcon. You will then update this variable depending on the state of the copy.
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: {
copyIcon: 'mdi-content-copy',
newAccount: {
login: 'GhostDestroyer69',
password: '',
},
},
methods: {
copy(field) {
const input = this.$refs[field].$refs.input
input.select()
document.execCommand('copy')
input.setSelectionRange(0, 0)
// Set icon to check
this.copyIcon = 'mdi-check'
// Reset icon to copy after 1 second
setTimeout(() => {
this.copyIcon = 'mdi-content-copy'
}, 1000)
}
}
})
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<div id="app">
<v-card class="col-12 col-md-8 col-lg-6 p-6 px-16" elevation="4">
<v-text-field
:value="newAccount.login"
label="Login"
outlined
readonly
:append-icon="copyIcon"
ref='login'
#click:append="copy('login')"
></v-text-field>
</v-card>
</div>
mdi has animation helpers like
append-icon="mdi-content-copy mdi-spin"
For example.
I've got a form in which the inputs are added dynamically with the v-for loop. Each field should be validated, and before user submit the form it should be checked wherever it's valid or not. The problem is that the this.$validator.validateAll() always return true, even if the inputs are invalid. What I'm doing wrong?
<div id="app">
<v-app id="inspire">
<v-flex md4 offset-md4>
<form data-vv-scope="photoForm">
<v-text-field v-for="index in 5"
:key="index"
:label="'photo' + index"
:error-messages="errors.collect('photoForm.photoName' + index)"
v-validate="'max:10'"
:data-vv-name="'photoForm.photoName' + index"
color="purple" autocomplete="on"
counter="10" >
</v-text-field>
</form>
<p>Is valid form? {{ validationResult }}</p>
</v-flex>
<v-btn #click="validate" color="purple" dark>
validate
</v-btn>
</v-app>
</div>
Vue.use(VeeValidate);
new Vue({
el: "#app",
data() {
return {
validationResult: ''
}
},
methods: {
validate() {
this.$validator.validateAll('photoForm').then(result => {
this.validationResult = result
})
}
}
});
And codepen where I reproduce the problem: https://codepen.io/anon/pen/jjrJdE
You need to store your form data somewhere so the validation has something to work on, I assume.
See https://codepen.io/cwg999/pen/MMjWNj?editors=1011
The main changes I made were to put your dynamically generated inputs into your data() and used that to reference them in the for-loop.
(note: you can also use v-model instead of :value/#input)
<v-text-field v-for="o,i in photoForm"
:key="i"
:label="o.label+ ' ' + (i+1)"
:error-messages="errors.collect('photoForm.photoName' + i)"
v-validate="'max:10'"
:name="'photoName' + i"
:value=o.value
#input="o.value = $event"
color="purple" autocomplete="on"
counter="10" >
</v-text-field>
data() {
return {
validationResult: '',
photoForm:[
{label:'Photo',value:''},
{label:'Photo',value:''}
]
}
},
I want to add the items in a v-select. for example, we dont have any item in a v-select and want to add it extrenaly.
<v-select
v-bind:label="Intelligence"
v-model="IntValues"
multiple >
</v-select>
When we write like this we will get only empty select list but how to add items into it externally
Here IntValues:[],
Or Editable list, like TodoMVC
new Vue({
el: '#app',
data() {
return {
selected: null,
items: []
}
},
methods: {
fetchItems() {
this.items = [
"A1",
"B2",
"C3"
]
}
}
})
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify/dist/vuetify.min.js"></script>
<script src="https://unpkg.com/babel-polyfill/dist/polyfill.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons' rel="stylesheet">
<link href="https://unpkg.com/vuetify#1.0.3/dist/vuetify.min.css" rel="stylesheet" />
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-layout row wrap>
<v-flex xs6>
<v-subheader>Standard</v-subheader>
</v-flex>
<v-flex xs6>
<v-select :items="items" v-model="selected" label="Select" single-line bottom></v-select>
</v-flex>
<div #click=fetchItems>FetchItems</div>
</v-layout>
</v-container>
</v-app>
</div>
You can modify the items later to update the value.
You can test with clicking the FetchItem to see the effect.
Watchers will do your work, add a watcher to your model and whenever it changes add value to your items.
You can refer this pen, it is using v-combobox which is having power of autocomplete.
https://codepen.io/saurabhtalreja/pen/yLMyJmE
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
select: ['Vuetify'],
items: [
'Programming',
'Design',
'Vue',
'Vuetify',
],
}
},
watch:{
select(val,prev){
console.log('New Input Value is' ,val);
console.log('Previous Value is' ,prev);
console.log('Model is = New Input ie. ', this.select);
console.log('Items Array is', this.items)
this.items.push(val);
console.log('New Items are', this.items)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<link href="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.4.11/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-row>
<v-col cols="12">
<v-combobox
v-model="select"
:items="items"
label="Combobox"
outlined
dense
></v-combobox>
</v-col>
</v-row>
</v-container>
</v-app>
</div>
If you have data in an array variable named values, then just assign it to IntValues.
ie,
this.IntValues = values;
If you have a single object say value, then just push it to the IntValues. ie, this.IntValues.push(value).
When the following component was inline, it was able to access rowData but as a referenced template it can't:
HTML:
<div id="app">
<div>
<row-component v-for="(row, index) in rows" :row-data="row" v-on:delete-row="deleteThisRow(index)"></row-component>
</div>
</div>
<script id="theRow" type="x-template">
row component: {{rowData}}
<button #click="$emit('delete-row')">Delete3</button>
</script>
JavaScript:
Vue.component('row-component', {
props: ["rowData"],
template: '#theRow'
})
new Vue({
el: '#app',
data: {
rows: ["line1", "line2", "line3", "line4", "line5"]
},
methods: {
deleteThisRow: function(index) {
this.rows.splice(index, 1);
}
}
})
How can I get the component to recognize rowData?
https://jsfiddle.net/edwardtanguay/k1tx3z1n/
Components should have only one root element
<div id="app">
<div>
<row-component v-for="(row, index) in rows" :row-data="row" v-on:delete-row="deleteThisRow(index)"></row-component>
</div>
</div>
<script id="theRow" type="x-template">
<div>
row component: {{rowData}}
<button #click="$emit('delete-row')">Delete3</button>
</div>
</script>
See the working fiddle