angular-forms
Javascript

Submitting AJAX Forms: The AngularJS Way

A lot of developers were submitting forms before AngularJS came out. There were so many different ways to submit forms that it could drive a person crazy… and they still can.

Today we’ll be looking at a simple form that used to be submitted using PHP and how to convert that to Angular. Using Angular for forms was one of those AHA moments for me. Even though it barely scratches the surface of Angular, it helps a user see the potential after seeing forms submitted and understanding the idea of two-way data-binding.

We will look at processing a form with just plain jQuery. The work needed to do this will be primarily in the javascript. We will submit the form, show errors, add error classes, and show/hide messages in javascript.

After that, we will be using Angular. The bulk of the work that was needed before will go away and lots of the things we did before (showing errors, adding classes, showing/hiding messages) will be so much simpler. Let’s dive in.

Submitting Forms with Just jQuery and AJAX: If you want to view a full article on submitting a form just using jQuery and AJAX, view our other article: Submitting AJAX Forms with jQuery.

Our Sample Form

We’ll be looking at two ways to submit this form:

  • The Old Way: AJAX Form with jQuery and PHP
  • The New Way: AJAX Form with AngularJS and PHP

Take a look at what we’ll be building. Super simple.

submitting-forms-with-angular

Form Requirements

  • Process the form without page refresh
  • Enter Name and Superhero Alias
  • Show errors if there are any
  • Turn inputs red if there are errors
  • Show success message if all is good

File Structure

We’ll only need two files to demonstrate.

  • index.html
  • process.php

Processing the Form

Let’s setup the PHP to process our form. This will be very minimal and will use http POST to get the form data.

Processing the Form: This won’t be that important to us. You can use any other language to process your form that you like.
// process.php

<?php

$errors         = array();  	// array to hold validation errors
$data 			= array(); 		// array to pass back data

// validate the variables ======================================================
	if (empty($_POST['name']))
		$errors['name'] = 'Name is required.';

	if (empty($_POST['superheroAlias']))
		$errors['superheroAlias'] = 'Superhero alias is required.';

// return a response ===========================================================

	// response if there are errors
	if ( ! empty($errors)) {

		// if there are items in our errors array, return those errors
		$data['success'] = false;
		$data['errors']  = $errors;
	} else {

		// if there are no errors, return a message
		$data['success'] = true;
		$data['message'] = 'Success!';
	}

	// return all our data to an AJAX call
	echo json_encode($data);

This is a very simple form processing script. We will just check if the data exists. If it does exist, don’t do anything. If it doesn’t exist, add a message to our $errors array.

To return our data to an AJAX call, we have to echo and json_encode. This is all we have to do with our PHP form processing. It will be the same for processing a form using normal jQuery AJAX or Angular.

Showing the Form

Let’s create our HTML that will show our form.

<!-- index.html -->

<!doctype html>
<html>
<head>
	<title>Angular Forms</title>

	<!-- LOAD BOOTSTRAP CSS -->
	<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css">

	<!-- LOAD JQUERY -->
        <!-- when building an angular app, you generally DO NOT want to use jquery -->
        <!-- we are breaking this rule here because jQuery's $.param will help us send data to our PHP script so that PHP can recognize it -->
        <!-- this is jQuery's only use. avoid it in Angular apps and if anyone has tips on how to send data to a PHP script w/o jQuery, please state it in the comments -->
   	<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>

	<!-- PROCESS FORM WITH AJAX (OLD) -->
	<script>
		<!-- WE WILL PROCESS OUR FORM HERE -->
	</script>
</head>
<body>
<div class="container">
<div class="col-md-6 col-md-offset-3">

	<!-- PAGE TITLE -->
	<div class="page-header">
		<h1><span class="glyphicon glyphicon-tower"></span> Submitting Forms with Angular</h1>
	</div>

	<!-- SHOW ERROR/SUCCESS MESSAGES -->
	<div id="messages"></div>

	<!-- FORM -->
	<form>
		<!-- NAME -->
		<div id="name-group" class="form-group">
			<label>Name</label>
			<input type="text" name="name" class="form-control" placeholder="Bruce Wayne">
			<span class="help-block"></span>
		</div>

		<!-- SUPERHERO NAME -->
		<div id="superhero-group" class="form-group">
			<label>Superhero Alias</label>
			<input type="text" name="superheroAlias" class="form-control" placeholder="Caped Crusader">
			<span class="help-block"></span>
		</div>

		<!-- SUBMIT BUTTON -->
		<button type="submit" class="btn btn-success btn-lg btn-block">
			<span class="glyphicon glyphicon-flash"></span> Submit!
		</button>
	</form>

</div>
</div>
</body>
</html>

Now we have our form. We’ve also used Bootstrap to make it not super ugly. Using the Bootstrap syntax, there is also a spot under each input to show a line of text for our errors.

submitting-forms-with-angular

Submit the Form with jQuery

Let’s go through the process of submitting the form with jQuery now. We will add all the code into our empty <script> tags.

<!-- index.html -->

...

	<!-- PROCESS FORM WITH AJAX (OLD) -->
	<script>
		$(document).ready(function() {

			// process the form
			$('form').submit(function(event) {

				// remove the past errors
				$('#name-group').removeClass('has-error');
				$('#name-group .help-block').empty();
				$('#superhero-group').removeClass('has-error');
				$('#superhero-group .help-block').empty();

				// remove success messages
				$('#messages').removeClass('alert alert-success').empty();

				// get the form data
				var formData = {
					'name' 				: $('input[name=name]').val(),
					'superheroAlias' 	: $('input[name=superheroAlias]').val()
				};

				// process the form
				$.ajax({
					type 		: 'POST',
					url 		: 'process.php',
					data 		: formData,
					dataType 	: 'json',
					success 	: function(data) {

						// log data to the console so we can see
						console.log(data);

						// if validation fails
						// add the error class to show a red input
						// add the error message to the help block under the input
						if ( ! data.success) {

							if (data.errors.name) {
								$('#name-group').addClass('has-error');
								$('#name-group .help-block').html(data.errors.name);
							}

							if (data.errors.superheroAlias) {
								$('#superhero-group').addClass('has-error');
								$('#superhero-group .help-block').html(data.errors.superheroAlias);
							}

						} else {

							// if validation is good add success message
							$('#messages').addClass('alert alert-success').append('<p>' + data.message + '</p>');
						}
					}
				});

				// stop the form from submitting and refreshing
				event.preventDefault();
			});

		});
	</script>

...


There’s a lot of code here to process the form. We have code to get the variables from the form, send it to our form using AJAX, check if there are any errors, and show a success message. On top of all that, every time the form is submitted, we want it to clear the past errors. Quite a lot of code.

Now if there is an error:

submitting-error

Or if there is a successful submission:

submit-success

Now let’s look at the same form, submitted with Angular. Remember, we don’t have to change anything about how our PHP processes the form and our application will function the same (showing errors and successes in the same places).

Submit the Form with Angular

We are going to set up our Angular application right inside the <script> tags we used earlier. So just delete everything inside and let’s begin.

Setting Up An Angular Application

The steps to set up our Angular application are:

  1. Load angular
  2. Set up a module
  3. Set up controller
  4. Apply module and controller to HTML
  5. Set up 2-way bound variables
  6. Set up errors and messages

It sounds like a lot, but in the end, we’ll use far less code and it will be much cleaner. It will also be much easier to create larger forms with many more inputs.

Angular Module and Controller

Let’s load up Angular and create our module and controller.

<!-- index.html -->

...

	<!-- LOAD JQUERY -->
	<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
	<!-- LOAD ANGULAR -->
	<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>

	<!-- PROCESS FORM WITH AJAX (NEW) -->
	<script>

		// define angular module/app
		var formApp = angular.module('formApp', []);

		// create angular controller and pass in $scope and $http
		function formController($scope, $http) {

		}

	</script>
</head>

<!-- apply the module and controller to our body so angular is applied to that -->
<body ng-app="formApp" ng-controller="formController">

...


We now have the foundation for our Angular app. We’ve loaded Angular, created a module and controller, and applied it to our site.

Next we will be showing off how 2-way binding works.

2-Way Data-Binding

This is one of the core ideas of Angular and one of its most powerful. From the Angular docs: “Data-binding in Angular web apps is the automatic synchronization of data between the model and view.” This means that the step where we have to grab data from the form using $('input[name=name]').val() is not required.

We bind data to a variable in Angular, and whenever it changes in either the Javascript or in the view, it changes in both.

To demonstrate data-binding, we’ll get our form inputs to populate a variable formData automagically. Let’s look back at our Angular controller that we applied to our page. We passed in $scope and $http.

$scope: The glue between application controller and the view. Basically variables are passed to and from our controller and view using $scope. For a more detailed definition, check out the docs.
$http: The Angular service that will help us do our POST request. For more information, check out the docs.

Getting the Variables Using Data-Binding

Alright, enough talk. Let’s apply this information to our form. It’s way simpler than it sounded above. We will add a line to the Angular controller and a line to the view.

<!-- index.html -->

...

	<!-- PROCESS FORM WITH AJAX (NEW) -->
	<script>

		// define angular module/app
		var formApp = angular.module('formApp', []);

		// create angular controller and pass in $scope and $http
		function formController($scope, $http) {

			// create a blank object to hold our form information
			// $scope will allow this to pass between controller and view
			$scope.formData = {};

		}

...


Now we have set up a formData object. Let’s populate it with our form inputs. Before we had to explicitly call each input and get its val(). Not anymore. We will use ng-model to bind a specific input to a variable.

<!-- index.html -->

...

	<!-- FORM -->
	<form>
		<!-- NAME -->
		<div id="name-group" class="form-group">
			<label>Name</label>
			<input type="text" name="name" class="form-control" placeholder="Bruce Wayne" ng-model="formData.name">
			<span class="help-block"></span>
		</div>

		<!-- SUPERHERO NAME -->
		<div id="superhero-group" class="form-group">
			<label>Superhero Alias</label>
			<input type="text" name="superheroAlias" class="form-control" placeholder="Caped Crusader" ng-model="formData.superheroAlias">
			<span class="help-block"></span>
		</div>

		<!-- SUBMIT BUTTON -->
		<button type="submit" class="btn btn-success btn-lg btn-block">
			<span class="glyphicon glyphicon-flash"></span> Submit!
		</button>
	</form>

	<!-- SHOW DATA FROM INPUTS AS THEY ARE BEING TYPED -->
	<pre>
		{{ formData }}
	</pre>

...


Now, Angular will now that each input is bound to formData. As you type into each input box, you can see the formData object being populated! It’s magic!

You do not need to use the word $scope in the view. Everything is considered to be nested inside of $scope.

Processing the Form

In our old form, we had to use jQuery to submit the form using $('form').submit(). Now we will use an Angular feature called ng-submit. To do this, we will add a controller function to process the form, and tell our form to use that controller function..

<!-- index.html -->

...

	<!-- PROCESS FORM WITH AJAX (NEW) -->
	<script>

		// define angular module/app
		var formApp = angular.module('formApp', []);

		// create angular controller and pass in $scope and $http
		function formController($scope, $http) {

			// create a blank object to hold our form information
			// $scope will allow this to pass between controller and view
			$scope.formData = {};

			// process the form
			$scope.processForm = function() {

			};

		}

...

	<!-- FORM -->
	<form ng-submit="processForm()">

...


Now our form knows to use that controller function when it is submitted. Now that we have that in place, let’s actually process the form using $http.

The syntax for processing a form will look very similar to the original way of doing it. The benefit is that we don’t have to grab our form data manually, or inject, hide, or add classes to show errors or success messages.

<!-- index.html -->

...

// process the form
$scope.processForm = function() {
	$http({
        method  : 'POST',
        url     : 'process.php',
        data    : $.param($scope.formData),  // pass in data as strings
        headers : { 'Content-Type': 'application/x-www-form-urlencoded' }  // set the headers so angular passing info as form data (not request payload)
    })
        .success(function(data) {
            console.log(data);

            if (!data.success) {
            	// if not successful, bind errors to error variables
                $scope.errorName = data.errors.name;
                $scope.errorSuperhero = data.errors.superheroAlias;
            } else {
            	// if successful, bind success message to message
                $scope.message = data.message;
            }
        });
};

...


That’s it for our form! None of that adding or removing classes. We don’t have to clear the errors every time we submit the form. We just have to bind the variables and the view will take care of the rest. This is great since the controller is for the data and the view is for showing the data.

jQuery POST vs Angular POST Sometimes you may see that your POST isn’t showing data on the server. This is because of the difference in the way jQuery and Angular serialize and send data. This comes down to the server language you are using and its ability to understand Angular’s data.

The above code is for a PHP server and jQuery is needed for the $.param function. There are ways to do it without jQuery but that’s pretty much the only reason jQuery was included for this example. Because it was easier.

The below cleaner syntax will work based on your server-side language. For more information on making AngularJS AJAX calls, read this great article: Make AngularJS $http Service Behave Like jQuery AJAX

Cleaner Syntax

This example sends data as a string and sets your headers. If you don’t need to do that kind of stuff and just want the cleanest Angular $http POST possible, we’ll use the shorthand method:


...
	$http.post('process.php', $scope.formData)
		.success(function(data) {
			...
		});
...

Definitely cleaner and a much easier to remember method than the above.

$http inside controllers: Ideally, you would move the $http request outside of the controller and into a service. This is just for demonstration purposes and we’ll do a write-up on services soon.

Showing the Errors and Messages in the View

We will use the directive ng-show and ng-class to handle our view. The Angular double brackets will place our variables where we need them also.

ng-show: Show or hide an element based on if a variable exists. Docs
ng-class: Add or remove a class based on if a variable exists (or some other expression). Docs

<!-- index.html -->

...

	<!-- SHOW ERROR/SUCCESS MESSAGES -->
	<div id="messages" ng-show="message">{{ message }}</div>

	<!-- FORM -->
	<form>
		<!-- NAME -->
		<div id="name-group" class="form-group" ng-class="{ 'has-error' : errorName }">
			<label>Name</label>
			<input type="text" name="name" class="form-control" placeholder="Bruce Wayne">
			<span class="help-block" ng-show="errorName">{{ errorName }}</span>
		</div>

		<!-- SUPERHERO NAME -->
		<div id="superhero-group" class="form-group" ng-class="{ 'has-error' : errorSuperhero }">
			<label>Superhero Alias</label>
			<input type="text" name="superheroAlias" class="form-control" placeholder="Caped Crusader">
			<span class="help-block" ng-show="errorSuperhero">{{ errorSuperhero }}</span>
		</div>

...

Our form is done! By using the power of Angular, we can move all of that stupid show/hide logic out of our javascript and into the view. Now our javascript file is free to just handle data and our view can do its thing.

Our classes and errors/success messages will hide and show if they are available. This is so much easier since we don’t have to worry about if we covered everything like in our old javascript. You don’t have to wonder if you remembered to hide those error messages on every form submit.

Angular Form Validation For more information on form validation, read up on our other article: AngularJS Form Validation.

Conclusion

Now we have our beautiful form fully converted to Angular. We’ve gone through a lot of concepts and hopefully as you play with them more, they will be easier to use.

We’ve gone through:

  • Creating an Angular module
  • Creating an Angular controller
  • 2-way data-binding
  • ng-model to bind inputs
  • ng-click to submit a form
  • Showing form errors using 2-way data-binding
  • Showing a div based on if a variable exists
  • Adding a class based on if a varible exists

These Angular techniques will carry over into much larger applications and there are so many great things that you can build. Have fun with Angular and stay tuned for more advanced articles. In the meantime, you can continue your Angular learning by diving into directives, services and factories, and so much more.

This article is part of the AngularJS Forms series.

Chris Sevilleja

Design, development, and anything in between that I find interesting.

View My Articles

Stay Connected With Us
hover these for magic

Get valuable tips, articles, and resources straight to your inbox. Every Tuesday.