Using RESTful Web APIs with AngularJS

  1. Overview
    1. AngularJS uses $http service (which uses XMLHttpRequest object) to make Ajax requests back to the server
    2. Typically create a service to encapsulate Ajax requests
    3. Since Ajax requests execute asynchronously, promises are used
  2. Promises
    1. $http uses promises when making HTTP requests so the script is not hung-up waiting for an HTTP response
    2. A promise is an object with different callbacks that are triggered when an event occurs
      // Immediately return from function call
      var promise = callThatRunsInBackground();
       
      promise.then(
      	function(answer) {
      		// Do something with answer
      	},
      	function(error) {
      		// Report error
      	},
      	function(progress) {
      		// Report progress
      	});			
      
    3. $http.get() returns a promise with four keys: data, status, headers, config
    4. These four params are sent to success callback
      // Make GET request
      var promise = $http.get('/api/students');
      promise.success(function(data, status, headers, config) {
      	$scope.students = data;
      });
       
      // Same thing
      var promise = $http.get('/api/students'); 
      promise.then(
      	function(response) {
      		$scope.students = response.data;
      	});
      
  3. Angular app that consumes the Student API
    1. In WebStorm, open the student API project you created earlier
    2. Create folder ng for all Angular code
    3. Create Angular app in ng/app.js
      angular.module('myApp', []);
      
    4. Create student service in ng/studentService.js
      angular.module('myApp')
          .service('studentService', ['$http', function($http) {
              this.getAll = function() {
                  // Return a promise
                  return $http.get('/api/students')
                      .then(function(response) {
                          return response.data;
                      });
              };
      
              this.create = function(student) {
                  return $http.post('/api/students', student);
              };
      
              this.update = function(student) {
                  return $http.put('/api/students', student);
              };
      
              this.delete = function(stuId) {
                  return $http.delete('/api/students/' + stuId);
              };
          }]);
      
    5. Create student controller in ng/studentController.js
      angular.module('myApp')
          .controller('studentController', ['$scope', 'studentService',
              function($scope, studentService) {
      
                  $scope.getStudents = function() {
      				// Get back a promise
                      studentService.getAll().then(function(students) {
                          $scope.students = students;
                      });
                  };
      
                  $scope.getStudents();
              }
          ]);
      
    6. Create app.html
      <!DOCTYPE html>
      <html>
      <head>
          <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.js"></script>
          <script src="ng/app.js"></script>
          <script src="ng/studentController.js"></script>
          <script src="ng/studentService.js"></script>
      
          <title>Student API Example</title>
      </head>
      
      <body ng-app="myApp" ng-controller="studentController">
          <h2>Student API Example</h2>
      
          <p ng-show="!students.length">No students</p>
          <ul ng-show="students.length > 0">
              <li ng-repeat="stu in students">
                  <strong>{{ stu.name }}</strong> -
                  {{ stu.gpa }} GPA
      			<span ng-if="!stu.enrolled">(Not enrolled)</span>
              </li>
          </ul>
      
      </body>
      </html>
      
  4. Implementing other CRUD operations
    1. Add a form to app.html
      <form>
      	ID: <input ng-model='stuId'>
      	<br>
      	Name: <input ng-model='stuName'>
      	<br>
      	Enrolled:
      	<label>
      		<input type="radio" name="enrolled" value="true" ng-model='stuEnrolled'>
      		Male
      	</label>
      	<label>
      		<input type="radio" name="enrolled" value="false" ng-model='stuEnrolled'>
      		Female
      	</label>
      	<br>
      	GPA: <input ng-model='stuGpa'>
      	<br><br>
      	<button ng-click='addStudent()'>Add Student</button>
      	<button ng-click='updateStudent()'>Update Student</button>
      	<button ng-click='deleteStudent()'>Delete Student</button>
      	<div style="color:green">{{ confirmMsg }}</div>
      	<div style="color:red">{{ errorMsg }}</div>
      </form>
      
    2. Adding a student in ng/studentController.js
      $scope.addStudent = function() {
      	$scope.errorMsg = '';
      	$scope.confirmMsg = '';
      	
      	// Expect minimally to have a name
      	if ($scope.stuName) {
      		var student = {
      			name: $scope.stuName,
      			gpa: $scope.stuGpa,
      			enrolled: $scope.stuEnrolled
      		};
      		
      		studentService.create(student).then(function() {
      			$scope.confirmMsg = 'Student was added.';
      		}, function(err) {
      			$scope.errorMsg = 'Unable to add student.';
      			console.log(err.data);
      		});
      	}
      	else {
      		$scope.errorMsg = 'Supply a name.';
      	}
      };
      
    3. Updating an existing student
      $scope.updateStudent = function() {
      	$scope.errorMsg = '';
      	$scope.confirmMsg = '';
      		
      	if ($scope.stuId) {		
      		var student = { _id: $scope.stuId };
      		
      		// Only update those items that the user supplied
      		if ($scope.stuName)
      			student.name = $scope.stuName;
      		if ($scope.stuGpa)
      			student.gpa = $scope.stuGpa;
      		if ($scope.stuEnrolled)
      			student.enrolled = $scope.stuEnrolled;
      
      		studentService.update(student).then(function() {
      			$scope.confirmMsg = 'Student was updated.';
      		}, function(err) {
      			if (err.data.message !== undefined)
      				$scope.errorMsg = err.data.message;
      			else
      				$scope.errorMsg = 'Unable to update student.';
      			console.log(err.data);
      		});
      	}
      	else {
      		$scope.errorMsg = 'Supply an ID.';
      	}
      };
      
    4. Deleting a student
      $scope.deleteStudent = function() {
      	$scope.errorMsg = '';
      	$scope.confirmMsg = '';
      	
      	if ($scope.stuId) {
      		studentService.delete($scope.stuId).then(function() {
      			$scope.confirmMsg = 'Student was deleted.';
      		}, function(err) {
      			if (err.data.message !== undefined)
      				$scope.errorMsg = err.data.message;
      			else
      				$scope.errorMsg = 'Unable to delete student.';
      			console.log(err.data);
      		});
      	}
      	else {
      		$scope.errorMsg = 'Supply an ID.';
      	}
      };