
New Year, first article! Let's get started. 🤩
So after several months of lockdown in Spain and really relaxing holidays, I worked hard on a plugin to bringDynamic Forms toVue3 andComposition API and finally, the stable 3.x version was released yesterday 🥳.
But... whatDynamic Forms even mean? Well is basically a vue component that renders forms and inputsdynamically based on a dataobject/schema
that represents the business logic.
<template><dynamic-form:form="testForm"/></template><scriptlang="ts">...setup(){constform=ref({id:'test-form',fields:{username:TextField({label:'Username',}),email:EmailField({label:'email',}),}})return{form}}...</script>
No more huge template files, no more "We need to do a new release because the client wants to change the username input label" 🤯. Forms schemas can be async and forms generated on go with an easy-going validation approach. All that for only26kB.
Still interested inquickly create forms in Vue 3.x? This article is for you.
What we are going to build?
Just a simple login form similar to the onehere. We are going to cover
- Email input with validation,
- Password input with validation
- Checkboxes
- Form submission
Create the demo app
For the app creation let's useVite⚡️
yarn create @vitejs/app my-login-demo--template vue-ts
Installation
To install just run:
yarn add @asigloo/vue-dynamic-forms# or, using NPMnpminstall @asigloo/vue-dynamic-forms
The installation and usage have changed to align with the new Vue 3 initialization process.
To create a new plugin instance, use thecreateDynamicForms
function.
// main.tsimport{createApp}from'vue';import{createDynamicForms}from'@asigloo/vue-dynamic-forms';constVueDynamicForms=createDynamicForms({// Global Options go here});exportconstapp=createApp(App);app.use(VueDynamicForms);
Theming
Vue Dynamic Forms is style agnostic, which means components have no predefined styles by default, so you can set them as you like. If you prefer a moreready-to-go
solution for styling you can import a defaulttheme
file from the package like this and override the variables like this.
// styles.scss$input-bg:#e2eb5d52;$input-border-color:#aec64c;@import'~@asigloo/vue-dynamic-forms/dist/themes/default.scss';
Login Form
Go to yourApp.vue
and add the<dynamic-forms />
component into your template:
<template><divclass="app"><dynamic-form:form="form"/></div></template>
Next step is to write down the form schema using aref
in thesetup
method
You can also defineform
as a computed property in case usingvue-i18n
labels or to reactively assign a value to any form property such as visibility or dropdown options
import{defineComponent,ref}from'vue';import{ EmailField,PasswordField,CheckboxField}from'@asigloo/vue-dynamic-forms';exportdefaultdefineComponent({name:'App',setup(){constform=ref({id:'login-form',fields:{email:EmailField({label:'Email',}),password:PasswordField({label:'Password',autocomplete:'current-password',}),rememberMe:CheckboxField({label:'Remember Me',}),},});return{form,};},});
Let's open our browser and check our new form with thevue-devtools
. If you don't have it install it yet and want to work with Vue3 support, I recommend you to install the Beta version on the chrome storehere. It includes awesome new stuff such as a Timeline for component events.
As you can see in the image above, each field was transformed into aFormControl
object containing crucial info for its rendering and behavior. With this, you can easily check and debug your forms.
It took what? 5 minutes?. 🤭
Form submission
Now that we have our form in place, we want to do something with the input data. There are two ways to do it:
- Use a
submit
button to trigger asubmit
event. (Recommended option, it also check if the form is valid). - Use the
change
event to get the latest state of the form values. (This one doesn't care about validation but it's helpful for autosave features for example)
Using asubmit
button.
If you add a button of typesubmit
just below the<dynamic-form />
with the attributeform
equal to theform.id
it will trigger the form submission internally.
<dynamic-form:form="form"@submitted="handleSubmit"@error="handleError"/><buttonclass="btn"submit="true":form="form?.id"> Sign In</button>
For this road, we have two (2) possible events:
submitted
in case the validation went well and the form isvalid
(retrieve all values) ☑️error
in case there is an error in the form (retrieves all errors) ❌
On change detection
TheDynamicForm component also offers achange
event in case you want to get the latest state of the form values right away. Is important to consider it will retrieve the valueswithout considering validation, (errors will still be shown at UI level) so you probably want to do a second validation outside.
<dynamic-form:form="form"@change="valuesChanged"/>
setup(){constformValues=reactive({});constform=ref({id:'login-form',fields:{// Form-fields},});functionvaluesChanged(values){Object.assign(formValues,values);console.log('Values',values);}return{form,valuesChanged,};},
Validation
Normally, forms submit data to a backend service, we want to make sure that the data required is sent, and is sent correctly so we don't end with errors in the console or "limbo" states in our application.
Let's make ouremail andpassword fields required for the submission. Just add a propertyvalidations
with an array of all the validation you want the field to have, in this case, let's import therequired
validator like this:
import{required,EmailField,Validator}from'@asigloo/vue-dynamic-forms`;
Then add it to your field definition:
email:EmailField({label:'Email',validations:[Validator({validator:required,text:'This field is required'}),],}),
If you try to submit the form empty, or you touch and blur the input without value it will adderror
classes to your component so you can style it accordingly
If you correct the validation, which in this case, it's just adding a value to the field and you blur, asuccess
class will be added to the control
What about checking if theemail
format is correct and adding a complex validation to your password?
By default,Vue Dynamic Forms contains the following validations:
- required
- min
- max
- URL
- minLength
- maxLength
- pattern.
So let's use theemail
andpattern
validator to our cause:
import{required,email,FormValidator,// ...}from'@asigloo/vue-dynamic-forms';
setup(){constemailValidator:FormValidator={validator:email,text:'Email format is incorrect',};// ...email:EmailField({label:'Email',validations:[Validator({validator:required,text:'This field is required'}),emailValidator,],}),}
Similar to this, let's use thepattern
validation, this function is special because it takes an argument which is theregex pattern you want to apply to the validation.
import{required,email,FormValidator,// ...}from'@asigloo/vue-dynamic-forms';
setup(){constpasswordValidator:FormValidator={validator:pattern('^(?=.*[a-z])(?=.*[A-Z])(?=.*)(?=.*[#$^+=!*()@%&]).{8,10}$',),text:'Password must contain at least 1 Uppercase, 1 Lowercase, 1 number, 1 special character and min 8 characters max 10',};// ...password:PasswordField({label:'Password',autocomplete:'current-password',validations:[Validator({validator:required,text:'This field is required'}),passwordValidator,],}),}
Wrap Up
So that's pretty much it, you can check the complete solutionhere (it also shows how to use withTailwindCSS)
Of course, this is a pretty simple example, but I will post more use cases in the near future, such asasync form data,i18n,custom fields, andthird-party components
If you have any questions feel free to open a discussion on the comment section or ping me on Twitter@alvarosaburido. I'm always hanging around.
We're also looking forcontributors to improve and maintain therepo, If you are interested in the challenge please DM me.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse