AngularJS Services for REST: Using the $http Service

The first service that I am going to use to complete the implementation of the example application is $http, which I described in Chapter 20. RESTful services are consumed using standard asynchronous HTTP requests, and the $http service provides all of the features that are required to bring the data into the application and write changes to the server. In the sections that follow, I’ll rewrite each of the data manipulation behaviors to use the $http service.

1. Listing the Product Data

None of the changes that I have to make to use Ajax is especially complex, and in Listing 21-5, you can see how I have changed the definition of the controller factory function to declare its dependencies.

I don’t want to embed the URL for the RESTful service throughout the application, so I have defined a constant called baseUrl for the root URL that provides access to the data. (You will need to change this URL if you have used a different port for Deployd or have installed it on a separate computer.) I then declare a dependency on baseUrl (which is possible because, as I explained in Chapter 18, constants are just simple services).

Listing21-5. Declaring Dependencies and Listing Data in the products.js File

angular.module(“exampleApp”, [])

.constant(“baseUrl”, “http://localhost:5500/products/”)

.controller(“defaultCtrl”, function ($scope, $http, baseUrl) {

$scope.displayMode = “list”;

$scope.currentProduct = null;

$scope.listProducts = function () {

$http.get(baseUrl).success(function (data) {

$scope.products = data;

 });

}

$scope.deleteProduct = function (product) {

$scope.products.splice($scope.products.indexOf(product), 1);

}

$scope.createProduct = function (product) {

$scope.products.push(product);

$scope.displayMode = “list”;

}

$scope.updateProduct = function (product) {

for (var i = 0; i < $scope.products.length; i++) {

if ($scope.products[i].id == product.id) {

$scope.products[i] = product; break;

}

}

$scope.displayMode = “list”;

}

$scope.editOrCreateProduct = function (product) {

$scope.currentProduct =

product ? angular.copy(product) : {};

$scope.displayMode = “edit”;

}

$scope.saveEdit = function (product) {

if (angular.isDefined(product.id)) {

$scope.updateProduct(product);

} else {

$scope.createProduct(product);

}

}

$scope.cancelEdit = function () {

$scope.currentProduct = {};

$scope.displayMode = “list”;

}

$scope.listProducts();

 });

The implementation of the listProduct method relied on the $http.get convenience method that I described in Chapter 20. I make a call to the base URL, which, as Table 21-4 noted, obtains the array of product objects from the server. I use the success method to receive the data that the server sends and assign it to the products property in the controller scope.

The last statement in the controller’s factory function calls the listProduct behavior to ensure that the application starts with some data. You can see the effect by loading products.html into the browser and using the F12 developer tools to look at the network requests that are made. You will see a GET request being made to the base URL, and the data will be displayed in the table element, as shown in Figure 21-7.

Tip You may notice a small delay between the contents of the tabieView.html file being displayed and the table element being populated. This is the time taken for the server to process the Ajax request and send the response, and it can be quite pronounced when the network or the service is busy. In Chapter 22, I show you how you can use the URL routing feature to prevent the view from being shown until the data has arrived.

2. Deleting Products

The next behavior I am going to reimplement is deleteProduct, which you can see in Listing 21-6.

Listing21-6.  Adding Ajax Requests to the deleteProduct Function in the products.js File

$scope.deleteProduct = function (product) {

$http({

method: “DELETE”,

url: baseUrl + product.id

}).success(function () {

$scope.products.splice($scope.products.indexOf(product), 1);

});

}

There is no $http convenience method for the HTTP DELETE method, so I have to use the alternative technique of treating the $http service object as a function and pass in a configuration object. I described the properties that can be set on a configuration object in Chapter 20, but I need only the method and url properties for this example.

I set the URL to be the base URL plus the id of the product I want deleted following the URL pattern I listed in Table 21-4. The $http service object returns a promise, and I use the success method to delete the corresponding product from the local array so that the server data and the local copy of it remain in sync.

The effect of this change is that clicking a Delete button removes the corresponding product from the server and the client. You can see the change both in the Deployd dashboard and, of course, in the browser that is running the example AngularJS application.

3. Creating Products

Adding support for creating new product objects requires the use of the HTTP POST method, for which there is an $http convenience method. You can see the changes I made to the createProduct behavior in Listing 21-7.

Listing 21-7. Creating Products in the products.js File

$scope.createProduct = function (product) {

$http.post(baseUrl, product).success(function (newProduct) {

$scope.products.push(newProduct);

$scope.displayMode = “list”;

});

}

The RESTful service responds to my create request by returning the object that it has created in the database from the data I sent. It is this object—and not the one passed as the argument to the behavior—that I add to the products array because the object returned by the server will have been assigned an id property. If I had stored the product object created from the ng-model directives, I would not have been able to edit or delete the object later because the server handles those operations based on the id. Once I have added the new object to the array, I set the displayMode variable so that the application displays the list view.

4. Updating Products

The last behavior I have to revise is updateProduct, which you can see in Listing 21-8.

Listing 21-8. Using Ajax in the updateProduct Behavior Defined in the product.json File

$scope.updateProduct = function (product) {

$http({

url: baseUrl + product.id,

method: “PUT”,

data: product

}).success(function (modifiedProduct) {

for (var i = 0; i < $scope.products.length; i++) {

if ($scope.products[i].id == modifiedProduct.id) {

$scope.products[i] = modifiedProduct;

break;

}

}

$scope.displayMode = “list”;

});

}

Updating an existing product object requires the HTTP PUT method for which there is no $http convenience method, meaning that I have to invoke the $http service object as a function and pass in a configuration object with the method and URL. The response from the server is the modified object, which I put into the local data array by checking each object in turn and comparing id values. Once I have added the modified object to the array, I set the displayMode variable so that the application displays the list view.

5. Testing the Ajax Implementation

You can see from the previous sections that implementing the Ajax calls to integrate the RESTful service into the application is a relatively simple task. I have skipped over some details that would be required in a real application, such as form validation and handling errors, but you get the idea: With just a little care and thought, it is easy to use the $http service to consume a RESTful service.

Source: Freeman Adam (2014), Pro AngularJS (Expert’s Voice in Web Development), Apress; 1st ed. edition.

Leave a Reply

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