Reuse of validation rules
-
I really like the fact that validations are now handled directly by the Quasar framework and not by an external package. They are also straightforward to define, including the error messages when the validation fails. But (as far as I can tell) using the same validation rules in more than one form requires repeating the code. Here is an example of what I expected I can do:
- Have a validations.js file with the list of rules to be used throughout my project
const emailPattern = /^(?=[a-zA-Z0-9@._%+-]{6,254}$)[a-zA-Z0-9._%+-]{1,64}@(?:[a-zA-Z0-9-]{1,63}\.){1,8}[a-zA-Z]{2,63}$/; export const email = val => emailPattern.test(val) || 'Please enter a valid email address'; export const required = val => !!val || 'Field is required';
- Use the rules in validations.js wherever validation is required. For example a login form would look something like:
<template> <div style="width: 500px; max-width: 90vw;"> <q-input v-model="form.userName" label="User" :rules="[required, email]" /> <q-input v-model="form.password" type="password" label="Password" @keyup.enter="loginClick" :rules="[required]" /> <div class="row" style="display: flex;align-items: center;"> <div class="col-4"> <small> Not registered? <span @click="openUserRegistration()">Register now</span> </small> </div> <div class="col-6"></div> <div class="col-2"> <q-btn rounded color="primary" label="Login" @click="loginClick" /> </div> </div> </div> </template> <script> import { required, email } from '../validations'; export default { ...................... } </script>
When I try running this code, eslint gives me a
no-unused-vars
on theimport
line as if therequired
andemail
are not used anywhere, but they are clearly used in the:rules
attributes on theq-input
tags. If I disable the eslint error for that line, the code runs, but no validation occurs. For example I can have an invalid e-mail address in theUser
field, and no error will be shown. Or I can have empty user and password and no error will be shown.The only way I could make the validations work is to either define the functions directly in the
:rules
attribute, which is really ugly and impractical, or I can define methods in the component like:methods: { // validations required(val) { return required(val); }, email(val) { return email(val); }, // end validations ....................... },
and change the
:rules
attribute in the template to be::rules="[this.required, this.email]"
While I like this second approach better than defining the functions directly in the attribute, it still defies the principle of re-usability.
My questions are: why is my first approach not working and how can I have reusable validation rules?
-
If you don’t have your methods, props, computeds, etc. inside the component’s options object (the code inside
export default{}
), then the component’s template has no knowledge of or rather can’t access those things. Just importing the methods does nothing and eslint is right for saying they aren’t used.Also,
this
isn’t needed inside of the template. You only need[required, email]
.Lastly, if you just do this,
methods: { email, required }
you have successfully added your imported methods into the component.
https://codesandbox.io/s/codesandbox-app-fs1hy
Scott
-
Scott, thank you for the example. It is indeed a lot more compact than what I had. It’s almost as good as what I wanted and I already modified my code to match it. My concern is that as concise as this is, it still requires me to mention the validation rules twice, once in the
import
and once in themethods
. I can easily see compilation errors in my future, when I forget to add a rule in one of the two places where I have to have it or delete it from one of the two places it is.I guess my question then is to the Quasar team: could a babel plugin be written to automatically generate the
methods: { email, required, }
when the code is compiled, and include the plugin with the Quasar framework?
-
you can make a boot file and register your methods as a vue prototype, if youre concern about importing and whatnot, then in your component call it
this.$myValHelper.required(someval)
in script part of your sfc and withoutthis
in the template.
I dunno why you are so concern with compile errors, in your trivial case a good ide would already warn you about error and won’t let you compile. -
I don’t get the concern either. The import and declaration in methods is one way. Globally binding the methods to Vue through a boot file is another.
Put it this way. If you imported the functions in any other code anywhere else, you’d have to also “use” them (i.e. write them out) somewhere in your JS code too.
Something else you can try is to construct/ design your own custom input component with whatever validation you need and “reuse” your custom component, where you need it. For instance a
<my-email-input>
component.Scott
-
I had the same issue and solved it like Scott did it. Thanks!
But how could this be made in validations.js?export const email = val => emailPattern.test(val) || $t('validAddress'); export const required = val => !!val || $t('required');
In other words: How put i i18n in there?
Because if I do like this above, $t and this.$t is unknown . -
Create regular methods and use them.
Scott
-
Ok, i did like this:
export const email = (val,msg) => emailPattern.test(val) || msg ...
and in the q-input of the component:
:rules="[ val => !!val || $t('required'), val => email(val,$t('validAddress')) ]"
I think that is what you meant with reg. methods, or?
-
Just as a side note: testing for the validity of an email address is almost impossible to do correct.
This video explains why( surprised me too btw ):
-
Sure. I am also surprised. So in fact, there’ll be no regex for that check?
Better to let user enter whatever he types? -
All regex pattern’s for testing an email addresses validity are probably not 100% correct.
As long as there is at least one ‘@’ present, it’s best to just to send it.