Forms are one of the most important aspects of any application. It is considered a good UX practice to keep the Save/Submit button disabled until the form contents have not changed. In this tutorial, you’ll take a look at how can you accomplish this behavior in a Nuxt/Vue app.
Contents
Creating a Form Template
First, you need to create a simple form that will help you to understand the concepts of computed and watch properties. In your index.vue file in the pages directory, add the following form template:
<template>
<form>
<label>Name</label>
<input v-model='form.name' />
<label>Age</label>
<input v-model='form.age' />
<button :disabled="!changed">Save</button>
<form>
</template>
In the above template, you have bounded your form
data model to form inputs using v-model
. The Save button will be disabled if the form fields have not changed
.
Writing Vuex Code
In this example, you’ll use Vuex Store’s state, actions, and mutations to store state and fetch your form data. In your index.js file in the store directory, add the following code:
// initialize the state variables
export const state = () => ({
form: {}
})
export const actions = {
// action to setup form data
// you can also do an api call as well
init({ commit }) {
const data = {
name: 'Ravgeet',
age: '21',
}
// add a commit mutuation for changing the state
commit('setFormData', data)
}
}
export const mutations = {
// mutation to change the state
setFormData(state, data) {
state.form = data
}
}
Writing Computed and Watch properties
At this point, your template and store are set. Next, you need to implement your application logic in your template’s script. In the pages/index.vue file, add the following code below the template:
<script>
import { cloneDeep, isEqual } from 'lodash'
export default {
data() {
return {
changed: false, // useful for storing form change state
form: {}, // data variable to store current form data binding
}
},
computed: {
// store the original form data
originalForm() {
return this.$store.state.form
}
},
watch: {
// by watching the original form data
// create a clone of original form data
// and assign it to the form data variable
originalForm() {
this.form = cloneDeep(this.originalForm)
},
// watch the changes on the form data variable
form: {
handler() {
// using lodash to compare original form data and current form data
this.changed = !isEqual(this.form, this.originalForm)
},
// useful to watch deeply nested properties on a data variable
deep: true,
},
},
created() {
// dispatch an action to fill the store with data
this.$store.dispatch('init')
}
}
</script>
In your terminal, run the following command to install lodash:
$ npm install lodash
In the above code:
- When the component is created, the
init
action is dispatched using thecreated
hook. This action causes a mutation in the store and fills theform
state variable. - The value of the computed property,
originalForm
is calculated as it is dependent upon theform
state variable. - As the value of
originalForm
is being watched using thewatch
hook, the code inside it is executed. A deep clone oforiginalForm
is made and assigned to theform
data variable. - Since the value of
form
is being watched, you use ahandler
anddeep
property to run your business logic. You simply check whether theform
andoriginalForm
variables are equal using Lodash.
At first, it looks like something very complex is going on but once you break down the things it makes sense.
Results
Navigate to your browser and check whether you have been able to achieve your purpose of disabling the form submit button if the form fields have not changed at all.
Voila! You have successfully implemented your workflow. This adds to the UX of your application and saves the user from frustration especially in long forms.