I need to create a registration mask and I want to make sure that the two passwords the user types in are identical before continuing but I cannot figure out how to do it in Vuetify.
I have tried creating a rule for it but it doesn't seem to work.
This is my code:
Template:
<v-row>
<v-col>
<v-flex md5>
<v-text-field v-model="pw1"
label="Password"
type="password"
:rules="pwdRules"
></v-text-field>
</v-flex>
</v-col>
<v-col>
<v-flex md5>
<v-text-field v-model="pw2"
label="Confirm Password"
type="password"
:rules="pwdConfirm"
></v-text-field>
</v-flex>
</v-col>
</v-row>
Script:
export default {
data: () => ({
pwdRules: [ v => !!v || 'Password required' ],
pwdConfirm:[ v => !!v || 'Confirm password', v => v === this.pw1 || 'Passwords do not match'],
}),
The funny thing is if I use this code snippet v => v === this.pw1 || 'Passwords do not match' it even makes Vuetify ignore the first rule which checks if the field is empty or not. If I delete this snippet the rule works correctly and checks if the field is empty but it obviously doesn't check if the two passwords are identical.
Vue component's data must be a function, not an arrow function since an arrow function doesn’t have a this. From Vue.js docs:
Don’t use arrow functions on an options property or callback, such as
created: () => console.log(this.a) or vm.$watch('a', newValue => this.myMethod()). Since an arrow function doesn’t have a this, this
will be treated as any other variable and lexically looked up through
parent scopes until found, often resulting in errors such as Uncaught TypeError: Cannot read property of undefined or Uncaught TypeError: this.myMethod is not a function.
You are referencing pw1 and pw2 which are not defined in data.
Here is Codepen
Related
I try to realise a upload page as part of a project. It's working fine but I wonder if there is a better way to reset my v-form for my inputs.
So here is what I do:
<v-container v-if="!success">
<v-flex>
<v-card>
<v-form ref="form" class="pa-5">
<v-select
...
>
</v-select>
<v-select
...
>
</v-select>
<v-text-field
...
/>
<form enctype="multipart/form-data">
<v-file-input
...
></v-file-input>
</form>
</v-form>
<v-card-actions>
<v-btn #click="addDocument">Add document</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-container>
<v-container v-if="success">
<v-flex>
<v-card>
<v-alert v-if="notification.show" :type="notification.type" class="pa-3">
{{notification.text}}
</v-alert>
<v-card-actions>
<v-btn #click="resetPage">Okay</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-container>
Two v-containers which will either be rendered if success is true or not. If success is false all the required inputs will be rendered and if its true (for me this means the upload was successfull) the second v-container should be rendered.
The second v-container shows just a message about the success and a "Okay" button which calls the resetPage function.
This function should reset all validations and clear all inputs.
What I've tried:
At first I tried this:
resetPage() {
this.success = false;
this.$refs.form.reset()
}
which obviously doesn't work because $refs.from is not rendered because its part of the first v-container.
So I thought I have to call the reset after it's been rendered.
So I tried this:
methods: {
resetPage() {
this.success = false;
}
},
updated() {
this.$refs.form.reset();
}
But quickly I learned that updated() is called if a input field changes or in my case one of the selects. I should have thought about this.
So I added allowReset and ended up with this:
methods: {
resetPage() {
this.success = false;
this.allowReset = true;
}
},
updated() {
if(this.allowReset) {
this.$refs.form.reset();
this.allowReset = false;
}
}
Its working like I need it to. But as I said updated() gets called everytime I select something or choose a file etc.
Is there maybe a better way to reach my goal?
Thank you in advance for all tips and tricks!
Add a v-model to your v-form. Whenever you reset the page by using this.success = false, the form should reset by itself.
When adding a v-model to a form it checks all of the rules set for the elements inside of that form. If they all pass the checks, the formValid will be true, otherwise false
simple example:
<div v-if="!success">
<v-form v-model="formValid">
<v-text-field v-model="a" :rules="[required]"></v-text-field>
</v-form>
<!-- Button will stay disabled as long as the form is invalid -->
<v-btn :disabled="!formValid">Save</v-btn>
</div>
<div v-else>
Success
</div>
And in your data:
formValid: false,
required: (v) => !!v || "Required" // Will print required if textfield is empty
Code Sandbox with exact example
https://codesandbox.io/s/veevalidate-components-vuetify-iftco
In the example above, when I enter a wrong value in the input field, the Validation state returns Valid == true, but it should return false.
I understand that this happens because the #input event method (resize) will run first and then it will assign the value to :value. In other words, vee-validate checks the existing value before the event is fired.
Not sure how to fix it so that the input value is first validated and then the method is run!
How to replicate problem:
Open the console
Change the value of the width field to 5
You will successfully get an error message under the field but the Valid flag in the console is set to true, even though the field is not valid after the method is done.
I am not sure how to fix this. I have been trying for hours..
<template>
<v-app>
<v-row>
<v-col v-for="(value, key) in fixture.dimensions" :key="key">
<ValidationProvider
:rules="`between:${fixture.limits[key].min},${fixture.limits[key].max}`"
v-slot="{ errors, valid }"
>
<v-text-field
:value="fixture.dimensions[key]"
#input="resize(key, valid)"
:label="key"
ref="key"
:min="fixture.limits[key].min"
:max="fixture.limits[key].max"
:error-messages="errors"
outlined
type="number"
></v-text-field>
</ValidationProvider>
</v-col>
</v-row>
</v-app>
</template>
<script>
import { ValidationProvider } from "vee-validate";
export default {
name: "App",
components: {
ValidationProvider
},
data: () => ({
fixture: {
dimensions: {
width: 1000,
height: 1500
},
limits: {
width: {
min: 300,
max: 1500
},
height: {
min: 300,
max: 1500
}
}
}
}),
mounted() {
console.log(this.fixture);
},
methods: {
resize(key, valid) {
console.log("valid?", valid);
this.fixture.dimensions[key] = event.target.value;
// this.fixture.iconObject.resize()
}
}
};
</script>
If you are not using v-model to manage the input, you should explicitly call validate yourself, like this:
<ValidationProvider
:rules="`between:${fixture.limits[key].min},${fixture.limits[key].max}`"
v-slot="{ errors, valid, validate }"
>
<v-text-field
:value="fixture.dimensions[key]"
#input="resize(key, $event, validate)"
...
></v-text-field>
</ValidationProvider>
resize(key, value, validate) {
validate(value).then(result => {
console.log("valid???");
console.log(result.valid);
//either way update value
this.fixture.dimensions[key] = value;
});
}
In the callback from validate, you get a result object that includes whether the result is valid, and also which rules failed (in result.failedRules) and any error messages in an array (in result.errors). See it working here:
https://codesandbox.io/s/veevalidate-components-vuetify-ynll5
lets say i want to make 2 text field and 1 v-select in vuejs using vuetify
Comodity ID (v-model = id)
Comodity Name (v-model = name)
v-select (v-model = selectType, :item= ['Using Document ID', id])
but whenever i try using the data such as this.id or id v-select always return No data available
I tried some of this topic but it doesn't solve my problem:
Vue Preselect Value with Select, v-for, and v-model
Vue dynamic v-model within v-for
Vue JS - Bind select option value to model inside v-for
this is my code :
<v-flex lg12 sm12>
<v-text-field label="Kode Penjualan" name="kodePenjualan" v-model="kodePenjualan">
</v-text-field>
</v-flex>
<v-flex lg12 sm12>
<v-text-field label="Komoditas" name="komoditas" v-model="komoditas">
</v-text-field>
</v-flex>
<v-flex lg12 sm12>
<v-select
v-model="selectDocs"
:items="tipeDocs"
label="Dokumen yang Dimiliki"
></v-select>
</v-flex>
this is my script:
data: () => ({
kodePenjualan: null,
komoditas: null,
selectDocs: null,
tipeDocs: [
'Dokumen Usaha Dagang Perantara',
kodePenjualan
],
}),
this is what i got right now
This is what i want to achieved
can someone help me with this?
Finally I can solve this, it seems i must computed tipeDocs properly to update my own :items,
computed: {
tipeDocs() {
return [
'Dokumen Usaha Dagang Perantara',
this.kodePenjualan
]
}
}
I hope this solution can help a lot of people who got stuck at the same problem with me
source : Answer for my question in Vue Forum
I want to build register form in Vue.
I think I did everything okay by the book. But my question is how to trigger the validation if I using v-form from Vuetify and vue-property-decorator.
Because all the examples they have this.$refs.form.validate()... For this form it's not working.
So, how to trigger the validation when I submit the form?
This is my code:
<template>
<v-container fluid fill-height>
<v-layout align-center justify-center>
<v-flex xs12 sm8 md6>
<v-container>
<v-card>
<v-toolbar dark color="primary">
<v-toolbar-title>Register</v-toolbar-title>
</v-toolbar>
<v-card-text>
<v-form v-model="loginValid">
<v-text-field v-model="form.name.value" prepend-icon="person" name="Name" label="Name" required></v-text-field>
<v-text-field v-model="form.email.value" :rules="form.email.rule" label="Email" required type="email" prepend-icon="person"></v-text-field>
<v-text-field prepend-icon="lock" v-model="form.password.value" :rules="form.password.rule" label="Password" type="password" required></v-text-field>
</v-form>
</v-card-text>
<v-card-actions class="pa-3">
<v-spacer></v-spacer>
<v-btn ref="btn-entrar" id="btn-entrar" color="primary" #click="submit">Register</v-btn>
<router-link to="/login" class="btn btn-link">Login</router-link>
</v-card-actions>
</v-card>
</v-container>
</v-flex>
</v-layout>
</v-container>
</template>
<script lang="ts">
import { Component, Watch, Prop } from 'vue-property-decorator';
import BaseComponent from '#/modules/common/components/baseComponent.vue';
import { State, Action, Getter } from 'vuex-class';
#Component({})
export default class RegisterPage extends BaseComponent {
public loginValid: boolean = false;
public form = {
name: { value: '' },
email: {
value: '',
rule: [
(v: string) => !!v || 'Email is required',
(v: string) => /.+#.+/.test(v) || 'E-mail must be valid'
]
},
password: {
value: '',
rule: [
(v: string) => !!v || 'Password is required',
(v: string) => v.length >= 8 || ''
]
}
};
public name: string = '';
public email: string = '';
public password: string = '';
constructor() {
super();
}
public submit() {
// i don't know if this form is valid or not :(
console.log('in submit');
}
}
</script>
I have not used Typescript, but ultimately, you'll have to validate each model onSubmit. So, in the submit() function that you have, do preventDefault(), validate your fields and if all okay then go ahead actually do submit the form to the backend.
Do read the guide for general workflow: https://v2.vuejs.org/v2/cookbook/form-validation.html
Also, do check out Vuelidate and VeeValidate which are simple validation frameworks for VueJS.
p.s.: see: using Vuelidate with Typescript issue first for good pointers.
I am trying to build some simple CRUD functionality for my app and I want to re-use the same form for both create and update.
my model im updating is Menu.
The way I am doing this (please let me know if there is a better way) is by having a method openForm(menu = null) on the new button I simply dont pass a menu and on the edit button I do.
openForm then checks if menu is null and if it is creates an empty menu object.
This is then stored in data() as menuForForm.
My form receives this as a prop and that is used for rendering my form.
My problem is that when I use the Vuetify $refs.form.reset() method to clear the form I get a whole load of errors relating to null values. It seems this is due to the validation rules as if I remove them its ok.
I can't understnad why a field value being null causes these problems, as if I bind a form to normal data() fields it works fine.
Here is my code:
Parent component
<template>
<v-flex xs12 sm6 lg4>
<v_form
v-if="menuForForm"
:menu="menuForForm"
>
</v_form>
</v-flex>
</template>
<script>
data() {
return {
menuForForm: null,
newMenu: {
id: '',
label: '',
url: '',
},
}
},
methods: {
openMenuForm(menu = null) {
menu ? this.menuForForm = JSON.parse(JSON.stringify(menu)) :
this.menuForForm = this.newMenu;
this.$store.dispatch('setShowForm', true);
},
}
</script>
Form component
<template>
<v-form ref="form" v-model="valid">
<v-text-field
v-model="menu.label"
:rules="labelRules"
label="Label"
required
>
</v-text-field>
<v-btn
color="primary"
:disabled="!valid"
#click="submit"
>
submit
</v-btn>
<v-btn
#click="clear"
>
clear
</v-btn>
</v-form>
</template>
<script>
data(){
return{
valid: true,
labelRules: [
v => !!v || 'Name is required',
v => v.length >= 3 || 'Label must be atleast than 3 characters'
],
}
},
methods:{
clear() {
this.$refs.form.reset();
}
}
</script>
Here is the error I get one I click clear:
[Vue warn]: Error in callback for watcher "value": "TypeError: Cannot read property 'length' of null"
found in
---> <VTextField>
[Vue warn]: Error in nextTick: "TypeError: Cannot read property 'length' of null"
found in
---> <VTextField>
TypeError: Cannot read property 'length' of null
at labelRules (Form.vue?c13f:61)
does anyone have any idea why this is happening, I have been on this for hours and its driving me mad.
Your rules should be
data(){
return{
valid: true,
labelRules: [
v => !!v || 'Name is required',
v => (v && v.length >= 3) || 'Label must be atleast than 3 characters'
],
}
}
Because on reset, form will set value to null
Demo: https://codepen.io/ittus/pen/KRGKdK