Chapter 3. Building a Minimal Front-End App with AngularJS in Seven Steps

Table of Contents

1. Step 1 - Set up the App's Structure
1.1. The start page index.html
1.2. Modules and routes
1.3. The start page view template main.html
1.4. View models in AngularJS
2. Step 2 - Using the Cloud Storage Service Parse.com
3. Step 3 - Implement the Retrieve/List All Use Case
4. Step 4 - Implement the Create Use Case
5. Step 5 - Implement the Update Use Case
6. Step 6 - Implement the Delete Use Case
7. Step 7 - Implement createTestData() and clearDatabase()
7.1. Adding several objects in one step
7.2. Delete several objects in one step
8. Run the App and Get the Code
9. Points of Attention

In this tutorial, we show how to build a minimal front-end web application with AngularJS and the cloud storage service Parse.com. The purpose of our example app is to manage information about books. That is, we deal with a single object type: Book, as depicted in Figure 3.1.

Figure 3.1. The object type Book.

The object type Book.

What do we need for such a data management app? There are four standard use cases, which have to be supported by the app:

  1. Create a new book record by allowing the user to enter the data of a book that is to be added to the collection of stored book records.

  2. Retrieve (or read) all books from the data store and show them in the form of a list (table).

  3. Update the data of a selected book record.

  4. Delete a book record.

These four standard use cases, and the corresponding data management operations, are often summarized with the acronym CRUD.

For entering data with the help of the keyboard and the screen of our computer, we can use HTML forms, which provide the user interface technology for web applications.

For maintaining a collection of persistent data objects, we need a storage technology that allows to keep data objects in persistent records on a secondary storage device, either locally or remotely. An attractive option for remote storage is using a cloud storage service, where data is stored in logical data pools, which may physically span multiple servers in a cloud infrastructure owned and managed by a cloud service company. A cloud storage service is typically reachable via a web API, which is often called a "REST API". For our minimal AngularJS app, we will use the cloud service platform Parse.com via its REST API.

1. Step 1 - Set up the App's Structure

In the first step, we set up our folder structure for the application. We pick a name for our app, such as "Public Library", and a corresponding (possibly abbreviated) name for the application folder, such as "publicLibrary". Then we create the following folder structure:

publicLibrary
|-- index.html
|-- js
|   |-- app.js
|   `-- controllers.js
|-- partials
|   |-- createBook.html
|   |-- deleteBook.html
|   |-- main.html
|   |-- showAllBooks.html
|   `-- updateBook.html
`-- src
    |-- AngularJS-route.js
    `-- angular.js

In addition to the index.html file for starting the app, we have three sub-folders:

  1. The js folder is used for all app-specific JavaScript files.

    • app.js has the task to define a name for our AngularJS app, to declare all dependences, also to organize the relationship between views, their corresponding controllers and even URLs.

    • controllers.js is used for implementing various functions.

  2. The partials folder holds all HTML-files for different sub-views, which will be replaced by AngularJS mutually exclusively into the body of index.html.

  3. The src folder holds all official libraries like angular.js and AngularJS-route.js.

1.1. The start page index.html

The entrance point of our web app, index.html, is used for including all files and creating a placeholder for different views:

<!DOCTYPE html>
<html ng-app="publicLibraryApp">
<head>
  <meta charset="UTF-8" />
  <title>Public Library with AngularJS</title>
  <script src="src/angular.js"></script>
  <script src="src/AngularJS-route.js"></script>
  <script src="js/app.js"></script>
  <script src="js/controllers.js"></script>
</head>
<body>
  <div ng-view="ng-view"></div>
</body>
</html>

The AngularJS attribute ng-app of the html element declares the root element of an AngularJS app with the name "publicLibraryApp"; another directive ng-view as an attribute of div element is responsible for handling routes by including the view template of the current route into the main layout index.html file, so that we don't need to redefine the same heading content for each view. In other words, other templates will be filled into the ng-view div element according to a configuration file app.js.

1.2. Modules and routes

The app.js file (located in the js folder) tells AngularJS the name of our app, defines dependencies, and manages the routes, controllers and URLs:

var publicLibraryApp = angular.module('publicLibraryApp',
        ['ngRoute', 'plControllers']);
publicLibraryApp.config(['$routeProvider', function ( $routeProvider) {
  $routeProvider
    .when('/main', {
      templateUrl: 'partials/main.html',
      controller: 'TestDataController'
    })
    .when('/showAllBooks', {
      templateUrl: 'partials/showAllBooks.html',
      controller: 'BooksController'
    })
    .when('/createBook', {
      templateUrl: 'partials/createBook.html',
      controller: 'BooksController'
    })
    .when('/updateBook', {
      templateUrl: 'partials/updateBook.html',
      controller: 'BooksController'
    })
    .when('/deleteBook', {
      templateUrl: 'partials/deleteBook.html',
      controller: 'BooksController'
    })
    .otherwise({
      redirectTo: '/main'
    });
}]);
publicLibraryApp.run(['$http', function ( $http) {
  // Provide credentials for accessing Parse.com
  $http.defaults.headers.common = {
    'X-Parse-Application-Id': 'Your_Application_ID',
    'X-Parse-REST-API-Key': 'Your_REST_API_Key'
  }
}]);

We define our app with the name "publicLibraryApp" and dependencies on the module plControllers (to be defined by us) and on the pre-defined AngularJS module ngRoute, which supports URL management providing routing, services and directives for AngularJS apps.

The module plControllers, which will collect all controllers of our app, is defined in the file js/controllers.js:

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

After declaring dependencies we configure our main module publicLibraryApp with publicLibraryApp.config for defining "routes", which are mappings from request URL paths to template/controller combinations, and with publicLibraryApp.run for providing application start-up information such as authentication credentials.

In conjunction with the ngView directive, application routes in AngularJS are declared via the $routeProvider, which is provided in module ngRoute to define a Route-ID for each view and corresponding controller.

For example, the third option of $routeProvider, .when('/createBook', ...) means that when the request URL path is "/createBook", the template partials/createBook.html will be rendered inside the ng-view div element and the app will be controlled by the user-defined controller BooksController.

1.3. The start page view template main.html

When index.html is requested and the request URL path is neither of "/main", "/showAllBooks", "/createBook", "/updateBook" or "/deleteBook", then the $routeProvider calls otherwise(), which takes care that "/main", in combination with the TestDataController, is used as the default route.

<menu>
  <li><a href="#/showAllBooks">
    <button type="button">List all Books</button>
  </a></li>
  <li><a href="#/createBook">
    <button type="button">Add a new Book</button>
  </a></li>
  <li><a href="#/updateBook">
    <button type="button">Update a Book</button>
  </a></li>
  <li><a href="#/deleteBook">
    <button type="button">Delete a Book</button>
  </a></li>
  <li><button type="button" ng-click="clearDatabase()">
      Clear database
  </button></li>
  <li><button type="button" ng-click="createTestData()">
    Create test data
  </button></li>
</menu>

In this view template, we provide a menu for choosing one of the CRUD data management operations via a corresponding page (such as createBook.html), or for creating test data with the help of the procedure createTestData(), or for clearing all data with clearDatabase(). The AngularJS event-handler attribute ng-click, defined for the button elements, allows specifying a controller method invocation to be executed when a corresponding click event has occurred.

1.4. View models in AngularJS

In an AngularJS app, the view model, which is simply called 'model', is the basis for writing the view and controller code. In the information design model shown in Figure 3.1 above, there is only one class, representing the (business) object type Book. In AngularJS, this class will be turned into a JS object as the value of the $scope property book, representing a view model, like so:

$scope.book = {
  "isbn": "",
  "title": "",
  "year": 0
};

The $scope object extends the app's $rootScope object (in the sense of prototype-based inheritance). AngularJS uses the $scope object, together with the information contained in the template and controller, to keep models and views separate, but in sync. Any changes made to the view model are propagated to the view, and any changes that occur in the view are propagated to the view model (this mechanism is called two-way data binding).