Introduction to AngularJS for jQuery developers

Introduction to AngularJS for jQuery developers

This is a simple and practical introduction to AngularJS written from the point of view of a developer who already has a firm knowledge of jQuery.

This is a simple and practical introduction to AngularJS written from the point of view of a developer who already has a firm knowledge of jQuery. jQuery and Angular work very well together, so the point is not to establish which solution is better for you but to start using Angular effectively.

Data binding

Binding data to a specific document fragment or structure is something that is implemented in two different ways by Angular and jQuery. jQuery uses the following approach:


$(function() {
	$( "[data-message]" ).each(function() {
		$( this ).text( $( this ).data( "message" ) );
	});
});

Data binding with jQuery

In jQuery there's always a direct manipulation of the DOM structure. Angular, instead, doesn't work this way:


<body ng-app="MyApp">
	<div ng-controller="MessageCtrl">
		<p>{{message}}</p>
	</div>	
</body>

The JavaScript code is as follows:


var app = angular.module('MyApp', []);

app.controller('MessageCtrl', ['$scope', function($scope) {
	$scope.message = 'Hello world';
}]);

Angular first initializes the main module of our application by using MyApp through the ng-app directive. This simply bootstraps our code. Then you define a controller, in this case MessageCtrl, linked by the ng-controller directive to our HTML code (called View in the Model View Whatever design pattern). This controller has a dependency injected into its constructor function, namely $scope, which is the current scope of our controller. What we do now? We define a property called message and finally magic happens: Angular finds the {{message}} block (note the variable's name within the block) and replaces this block with the value of our property.

No DOM manipulation required. Clean, simple and concise. It's a little bit difficult to grasp at first because Angular forces you to structure your code in a specific way. A well-organized way.

Data binding

Two-way data binding

We have a text input and we want to show on the page what the user is typing in real time. In jQuery we can write the following code:


$(function() {
	var message = "Hello world",
		$output = $( "p" ).eq( 0 ),
		$input = $( ".form-control" );

		$input.val( message );
		$output.text( message );

		$input.keyup(function() {
			var value = $( this ).val();
			$output.text( value );
		});
});

Two-way data binding with jQuery

It works well, so why bother? But the Angular team has found a way to make it even simpler than this:


<body ng-app="MyApp">
	<div ng-controller="MessageCtrl">
		<p>{{message}}</p>
		<p><input type="text" class="form-control" ng-model="message" ng-value="message" /></p>
	</div>	
</body>

The JavaScript code:


var app = angular.module('MyApp', []);

app.controller('MessageCtrl', ['$scope', function($scope) {
	$scope.message = 'Hello world';
}]);

Two-way data binding

The magic here is performed by the ng-model directive that refers to the message property. When a user types something in the text field, the value of our property is automatically updated. Also note that Angular provides specific directives that enhance the traditional HTML attributes, such as ng-value.

Working with data

Suppose that we have a list of contacts that we want to show on a page. In jQuery this involves looping through an array, build an HTML string and finally call the .html() method to insert our data into a specific element.

In Angular things get separated. First, the controller:


app.controller('DataCtrl', ['$scope', function($scope) {
	$scope.data = [
		{
			name: 'Louisa Newman',
			phone: '+1 (935) 582-3513'
		},
		{
			name: 'Irene Lindsey',
			phone: '+1 (871) 573-3578'
		},
		{
			name: 'Case Bright',
			phone: '+1 (917) 457-3358'
		},
		{
			name: 'Davidson Clarke',
			phone: '+1 (850) 526-2418'
		},
		{
			name: 'Nolan Stevenson',
			phone: '+1 (894) 584-3227'
		},
		{
			name: 'Sonia Ferguson',
			phone: '+1 (815) 447-2996'
		}
	];
}]);

Then our view:


<body ng-app="MyApp">
	<div ng-controller="DataCtrl">
		<ul class="contacts">
			<li ng-repeat="item in data">
				<h4><i class="glyphicon glyphicon-user"></i> {{item.name}}</h4>
				<div>{{item.phone}}</div>
			</li>
		</ul>
	</div>	
</body>

Working with data 1

The ng-repeat takes care of the loop and it provides access to every single object in the array. As you can see, our array has been declared as a property of the controller's scope.

Now I bet you're tired to see only static properties in the scope and you want to see what happens when we create methods. Let's add the ability to add or remove a contact to our controller:


app.controller('DataCtrl', ['$scope', function($scope) {
	$scope.data = [/*...*/];


	$scope.addContact = function(name, phone) {
		if($scope.dataForm.$valid) {
			$scope.data.push({
				name: name,
				phone: phone
			});
		}
	};

	$scope.removeContact = function(name) {
		for(var i = 0; i < $scope.data.length; ++i) {
			if($scope.data[i].name == name) {
				$scope.data.splice(i, 1);
			}
		}
	};
}]);

And in our view:


<body ng-app="MyApp">
	<div ng-controller="DataCtrl">
		<ul class="contacts" ng-if="data.length > 0">
			<li ng-repeat="item in data">
				<h4><i class="glyphicon glyphicon-user"></i> {{item.name}} 
					<a href="" ng-click="removeContact(item.name)">
						<i class="glyphicon glyphicon-remove"></i>
					</a>
				</h4>
				<div>{{item.phone}}</div>
			</li>
		</ul>
		<form novalidate name="dataForm" ng-submit="addContact(name, phone)">
			<p><input type="text" name="name" class="form-control" ng-model="name" placeholder="Name" required /></p>
			<p><input type="text" name="phone" class="form-control" ng-model="phone" placeholder="Phone" required /></p>
			<p><input type="submit" class="btn btn-primary" value="Add contact" /></p>	
		</form>
	</div>	
</body>

Working with data 2

The main changes are in our view. We use the ng-if directive to test if there are contacts to show. If there are none, the list won't be created. Then we attach a click handler using the ng-click directive. Inside this directive we call our removeContact() method which accepts the name of a contact as its sole argument. Note that within our loop we're invoking this method on the current contact object.

We don't need the default HTML5 validation on our form, so we use the novalidate attribute to stop the browser's behavior. We assign a name attribute to the form, so we can reference it in our controller's scope. When the form is submitted, we call our method that creates a new contact. This method checks whether a name and a phone number have been actually inserted.

Why name and phone are not undefined? The two-way data binding automatically creates them and assign it to the controller's scope if they don't exist. Really handy!

AJAX

So far it's been easy to work with data because everything was already in place. Let's rewrite our previous example by using AJAX. In jQuery we can write the following code:


var getData = function( url, callback ) {
	$.when( $.getJSON( url ) ).done(function( response ) {
		callback( response );
	});
};

var parseData = function( data, element ) {
	var html = "";
	for( var i = 0; i < data.length; ++i ) {
		html += "<li>";
		html += "<h4><i class='glyphicon glyphicon-user'></i> ";
		html += data[i].name;
		html += " <a href='' class='remove'><i class='glyphicon glyphicon-remove'></i></a>";
		html += "</h4>";
		html += "<div>" + data[i].phone + "</div>";
		html += "</li>";
	}

	element.html( html );
};

$(function() {
	$( document ).on( "click", ".remove", function( e ) {
		e.preventDefault();
		$( this ).parents( "li" ).remove();
	});

	$( ".dataForm" ).on( "submit", function( e ) {
		e.preventDefault();
		var name = $( this ).find( "[name='name']" ).val();
		var phone = $( this ).find( "[name='phone']" ).val();

		if( phone !== "" && name !== "" ) {
			var html = "<li>";
			html += "<h4><i class='glyphicon glyphicon-user'></i> ";
			html += name;
			html += " <a href='' class='remove'><i class='glyphicon glyphicon-remove'></i></a>";
			html += "</h4>";
			html += "<div>" + phone + "</div>";
			html += "</li>";

			$( ".contacts" ).append( html );	
		}
	});

	getData( "api/data.json", function( response) {
		parseData( response, $( ".contacts" ) );
	});
});

AJAX in jQuery

It should be clear now that jQuery 90% of the times manipulates the DOM directly either by injecting HTML code directly or appending new elements to an existing structure. Angular works in a different way.

Every property in the scope is live. This means that Angular updates a property whenever a change occurs, even after an AJAX request. In Angular the JavaScript code is as follows:


app.controller('DataCtrl', ['$scope', '$http', function($scope, $http) {
	$scope.data = [];

	$http.get('api/data.json').then(function(response) {
		$scope.data = response.data;
	}, function(response) {

	});


	$scope.addContact = function(name, phone) {
		if($scope.dataForm.$valid) {
			$scope.data.push({
				name: name,
				phone: phone
			});
		}
	};

	$scope.removeContact = function(name) {
		for(var i = 0; i < $scope.data.length; ++i) {
			if($scope.data[i].name == name) {
				$scope.data.splice(i, 1);
			}
		}
	};
}]);

AJAX 1

$http is defined as follows:

The $http service is a core Angular service that facilitates communication with the remote HTTP servers via the browser's XMLHttpRequest object or via JSONP.

Note that this service must be explicitly injected into our controller: this happens because every dependency must be always injected in Angular. Despite its asynchronous nature, implemented with promises, when the data is received and associated with the data property, it immediately becomes available in the scope.

Complete examples

Introduction to AngularJS for jQuery developers

API Reference

AngularJS: API: API Reference