Handling Forms in Vue.js

Introduction

When building web applications, there is always the possibility of working with forms. Learning to handle them as you work with different tools is very important. In this tutorial, you will see how to handle forms in Vue.js.

Get Started

Create a new Vue project using Vue-CLI. If you do not have Vue-CLI installed on your machine, you can do so by running:

npm install -g vue-cli

That will install Vue-CLI globally on your machine. You can go ahead to create the project by running:

vue init webpack vue-forms

That will create a new Vue project, using the Webpack template. Navigate to the directory that was created for the project, and install the dependencies.

cd vue-forms
npm install

You will be making use of Bootstrap in this tutorial. Open your index.html file and make it look like this.

#index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>vue-forms</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"></head>
  <body>
    <div id="app">
    </div>
    <script src="/dist/build.js"></script>
  </body>
</html>

Nothing fancy here—just the link element tag for our Bootstrap stylesheet. You will build a simple registration form from scratch, and bind the values entered into the form using v-model. When working with forms in Vue.js, you bind form input values to the Vue instance using the v-model directive.

Input Binding

Let’s get started with some simple text input to collect the email address, password, and age of the user. Open up your App.vue file.

Edit the template section to look like what I have below.

#src/App.vue

<template>
  <div class="container">
    <form>
      <div class="row">
    			<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
					<h1>Enter your information</h1>
					<hr>
					<div class="form-group">
						<label for="email">Mail</label>
						<input type="text" id="email" class="form-control" v-model="userData.email">
					</div>
					<div class="form-group">
						<label for="password">Password</label>
						<input type="password" id="password" class="form-control" v-model="userData.password">
					</div>
					<div class="form-group">
						<label for="age">Age</label>
						<input type="number" id="age" class="form-control" v-model="userData.age">
					</div>
				</div>
      </div>
    </form>
  </div>
</template>

In the above, you are using the v-model directive to bind the inputs for email, password, and age to an object. Here, the object is called userData. The userData object is supposed to have different properties—email, password and age—where the values of the inputs will be saved.

The userData object has to be defined in the data option of your Vue instance.

<script>

    export default {
		data () {
			return {
				userData: {
					email: '',
					password: '',
					age: 40
				}
			}
		}
	}

</script>

With that, you have established a two-way binding. You can now access the values for the email, password, and age inputs as userData.email, userData.password, and userData.age respectively. From the above, you set the default value for the age object. Without entering a value, the value is set at 40. This is an example of how you can implement defaults when working with forms in Vue.js.

Input Modifiers

Now go to the form group for your password to make the password visible. The form group should look like this.

<div class="form-group">
  <label for="password">Password</label>
  <input type="password" id="password" class="form-control" v-model="userData.password">
  <p>{{ userData.password }}</p>
</div>

As you enter inputs in the input box, each letter you enter gets displayed. Vue.js gives you the option to halt display of the values till you move to another input field or another place in the page. To do this, you have to edit the v-model directive by adding a lazy modifier, like so.

<input type="password" id="password" class="form-control" v-model.lazy="userData.password">

This does not listen to the input event, but the change event that gets fired when you are done with that input field. Another modifier that can come handy is the trim modifier. If used for the email field, it will look like this.

<input type="text" id="email" class="form-control" v-model.trim="userData.email">

This is the same way you used the lazy modifier. The trim modifier will remove any extra space from the entered values.

Working with textarea is like what you did above. The only difference is that interpolation will not work. Let’s add a textarea to our form, inside the form tag.

<div class="row">
    <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 form-group">
		<label for="message">Message</label><br>
		<!-- Interpolation between <textarea>{{ test }}</textarea> doesn't work!-->
		<textarea id="message" rows="5" class="form-control" v-model="message"></textarea>
	</div>
</div>

Update the model to look like this.

<script>

    export default {
		data () {
			return {
				userData: {
						email: '',
						password: '',
						age: 40
				},
				message: 'This is a placeholder text'
			}
		}
	}
</script>

Checkboxes and Radio Buttons

Checkboxes give users the opportunity to select more than one option. When implementing this, the values are bound to the same array.

So, in your template, you should add this.

<div class="row">
    <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
		<div class="form-group">
			<label for="designer">
				<input type="checkbox"    id="designer" value="Designer" v-model="occupation"> Designer
			</label>
			<label for="developer">
				<input type="checkbox" id="developer" value="developer" v-model="occupation"> Developer
			</label><!-- Also show for single checkbox with true/ false -->
		</div>
	</div>
</div>

While the data model is updated too.

data () {
    return {
		userData: {
			email: '',
			password: '',
			age: 40
		},
		message: 'This is a placeholder text',
		occupation: []
	}
}

If you are working with radio buttons, where the user can only select one option, you do not make use of an array. Let’s add radio buttons to the registration form.

<div class="row">
    <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 form-group">
		<label for="male">
			<input type="radio" id="male" value="Male" v-model="gender"> Male
		</label>
		<label for="female">
			<input type="radio" id="female" value="Female" v-model="gender"> Female
		</label>
	</div>
</div>

The corresponding data model will look like this.

data () {
    return {
		userData: {
			email: '',
			password: '',
			age: 40
		},
		message: 'This is a placeholder text',
		occupation: [],
		gender: 'Female
	}
}

Vue.js knows that both radio buttons belong to the same group, so it only allows the selection of one. It also stores the value of the selected radio button in the gender property; this is done automatically for you.

Handling Drop-Downs

The v-model directive is also used for dropdowns. In the template, you are to loop through a collection of values, as these values are automatically populated in your form.

Here is a drop-down that loops through a list; the list will be defined in the data model.

<div class="row">
    <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 from-group">
		<label for="expertise">Expertise</label>
			<select id="expertise" class="form-control" v-model="selectedExpertise">
				<option v-for="expertise in expertises">{{ expertise }}</option>
			</select>
	</div>
</div>

The data model should look like this.

data () {
    return {
		userData: {
			email: '',
			password: '',
			age: 40
		},
		message: 'This is a placeholder text',
		occupation: [],
		gender: 'Female,
		selectedExpertise: 'Professional',
		expertises: ['Newbie', 'Beginner', 'Professional', 'Expert']
	}
}

The binding is done on the select tag element, and not on the individual options. A default option is set in the data model when a user selects another option, and the selectedExpertise gets updated.

Form Submission

Here, you’ll add a submit button. You’ll need to prevent the submit button from submitting the form to the server, which is its default behaviour. You’ll substitute that with displaying the form on the page. 

Thus there will need to be a method that changes the value of the display section to true. When true, the display section is expected to show the values of the form. Start by adding the submit button.

<div class="row">
    <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
		<button class="btn btn-primary" @click.prevent="submitted">Submit!</button>
	</div>
</div>

Here, you’re listening for the click event, and when the button gets clicked, you want to call a method. This method needs to be added to the script section of your code.

<script>
    export default {
		data () {
			return {
				userData: {
					email: '',
					password: '',
					age: 40
				},
				message: 'This is a placeholder text',
				occupation: [],
				gender: 'Female,
				selectedExpertise: 'Professional',
				expertises: ['Newbie', 'Beginner', 'Professional', 'Expert']
			}
		},
		methods: {
				submitted() {
						this.isSubmitted = true;
				}
		}
  }
</script>

With that done, you can add the display section, after the closing tag of the form.

<hr>
<div class="row" v-if="isSubmitted">
    <div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
		<div class="panel panel-default">
			<div class="panel-heading">
				<h4>Your Data</h4>
			</div>
			<div class="panel-body">
				<p>Mail: {{ userData.email }} </p>
				<p>Password: {{ userData.password }}</p>
				<p>Age: {{ userData.age }}</p>
				<p style="white-space: pre">Message: {{ message }}</p>
				<p><strong>Interest</strong></p>
				<ul>
					<li v-for="item in interest">{{ item }}</li>
				</ul>
				<p>Gender:  {{ gender }}</p>
				<p>Priority: {{ selectedExpertise }}</p>
			</div>
		</div>
	</div>
</div>

With that, when the submit button gets clicked, the values entered in the form will be displayed.

Conclusion

At this point, you can work effectively with forms when building applications using Vue.js. If you’re looking for additional resources to study or to use in your work, check out what we have available in the Envato Market.

You learned how to work with all possible parts of a form you might encounter in your journey as a developer. You’ve tried your hand at inputs, select options, radios, checkboxes, and textarea. 

Thanks for reading!

Leave a Reply

Your email address will not be published. Required fields are marked *