Form Validation With Quasar Framework and the Vue.js Composition API
Many of the applications I have built over my career have been CRUD apps. Take something traditionally stored on paper or a spreadsheet, get it into a database easily queried by an API, and build an interface for elegantly interacting with the data.
To build an interface for one of these applications, you need the ability to create a solid form. Something visually appealing, readable, understandable, and leading. All frameworks produce these results in different (for better or worse) ways. This article will examine how to do it with the Quasar Framework, and Vue.js.
The Quasar Way
While there are other popular libraries (like Vuelidate) out there for validating forms, Quasar offers a lot validation out-of-the-box which makes much of these libraries superfluous. We will examine these features by building a “create an account” form to illustrate how it all works.
I will not spend time showing how to build a Quasar app. It is easy to do in just a few minutes with the Quasar CLI getting started guide. The project settings we will be using are:
- App with Quasar CLI
- Project folder: ‘quasar-validation’
- Quasar V2
- Typescript
- Webpack
- “Quasar Validation Example” for names and descriptions
- Composition API
- SCSS
- ESLint
- Prettier
Create Our Form Component
In the \src\components
folder, create a new file called CreateAccountForm.vue
. This is the file where we will be doing all of our work.
Configure Our Route
The last thing we need to do is route to this component in some way. In the \router
folder, open routes.ts
and edit the child import path for ''
to point to our new CreateAccoutForm.vue
component.
Building a Template
The first thing we will want to do is populate our CreateAccountForm.vue
component with some template HTML/CSS.
CSS Classes like column
and q-pa-sm
are Quasar styling classes used for quick and easy layouts. This helps keep the amount of styling we need to write to a minimum. The rest of the <q-name>
tags are Quasar UI components.
You should now have something that looks like this.
Modeling The Form Components
The next thing we will need to do is bind all the UI components to some data model so that we can capture and track what the user types in. We will be using Vue.js Composition API. This is new to Vue 3 and helps remove much of the boiler plate Options API code as well as make it more readable.
Add the following code to the bottom of the CreateAccountForm.vue
component file.
Here we are defining typescript as the code language using the lang
attribute. Adding setup
to the <script>
tells Vue that all this code gets wrapped in the component’s setup function and is available to the template.
Next, we have defined a type for the state of our form and used Vue’s Reactivity API to create a state object for tracking the form data.
Bind the Model
We can now bind all our formState
properties to the different UI components using the v-model
tag for each input. For example:
<q-input label="Name *" v-model="formState.name"></q-input>
Last, we want our form to run the submitForm
function when the ‘Create Account’ button is pressed. Add that to the q-form
tag.
<q-form @submit="submitForm">
We should now be able to fill out one or more of the form fields, click the ‘Create Account’ button, and see the state of our form logged in the browsers console!
Writing Validators
We now want to harden our form against user error by making sure all required fields have been filled out and correctly. Some of this has already been solved with Quasar’s mask attribute on the phone input.
For the name
input, we just want to make sure that the user has filled in something for a name. The rules
attribute of Quasar’s input component takes an array of validators. These are simple boolean result functions which do something with the value and return error text if it is false.
<q-input
label="Name *"
v-model="formState.name"
:rules="[
(val) => (val && val.length > 0) || 'Name must be filled in.',
]"
></q-input>
If we focus the field and then move off it, we will now see an error. You will also notice that the form will no longer submit and will automatically focus the name field with the error (Thank you Quasar!).
Email is a little more complicated to check, so we will write a function in the <script>
area of our template and pass in the value. We will expect the function to return a boolean to whether it passes the email check.
function validateEmail(email: string): boolean {
return /[a-z0-9]+@[a-z]+\.[a-z]{2,3}/.test(email);
}
We are using regex and the test function to compare the string.
In our email component call the function with the same :rules=""
attribute to validate the value.
<q-input
label="Email *"
v-model="formState.email"
:rules="[
(val) => validateEmail(val) || 'Must be a valid email.'
]"
></q-input>
Password is our most intense thing to validate. Here, we have a list of criteria we want the user to follow. We will want to aid them as they type in their password, letting them know what criteria they have successfully met.
Somewhere in our <script>
tag add the following code.
In this code we have another reactive state object for watching what criteria the user has successfully completed. The validatePassword()
function will be called by our password component and will update the state object.
We will now want to bind changes to the icon and color of each password criteria to reflect the progress the user is making.
<div>
<q-icon
:name="validPassword.length ? 'check_circle' : 'cancel'"
:color="validPassword.length ? 'positive' : 'negative'"
></q-icon>
Must be at least 12 characters long.
</div>
Last, we need to write a validator to compare the value of the password with the confirmation field. We also want to disable the confirmation field until the password has been correctly filled out.
<q-input
label="Confirm Password *"
v-model="formState.password.confirm"
:disable="!validatePassword(formState.password.value)"
:rules="[
(val) =>
(val && val === formState.password.value) ||
'Must match password.',
]"
></q-input>
We should now have a form that looks something like this as we fill it out.
Our component code should look something like this.
Conclusion
Quasar offers a simple and straight forward approach to form validation which is easily extensible. While other form validation libraries offer some additional features which may be nice for larger projects, smaller projects could probably get by just fine without them.
Typescript along with the new Composition API, removes a lot of the classic boiler plate code and reduces the number of mistakes through strong typing.