Tuesday, 5 March 2013

AJAX using Angular JS

Angular JS defines a service, $http, that is capable of communicating with remote servers over HTTP using XmlHttpRequest. $http includes a service that takes a single configuration object where we configure all required properties for the remote asynchronous call. Following is the syntax of using $http service with configurations:
$http({method:’<method>’, url: ‘<service-url>’})
 .success(function(data, status, headers, config){
  //Logic to be executed upon successful completion of the request
  //Will be called asynchronousy
 })
 .error(function(data, status, headers, config){
 //Logic to be executed when the request is unsuccessful
 //Will be called asynchronously
});

We also have shortcut methods to send get, post, put, delete, head and JSONP requests. These methods accept URL, config. Post and put methods accept input data also as a parameter. To learn more about these methods and the input parameters, refer to $http service documentation.

 Let’s continue with our shopping cart example which I have used in all earlier posts (Last post in this series is Form validation using Angular JS). I created an ASP.NET Web API controller to operate on the cart items. We have to replace the logic of operating with cart items with AJAX calls to the Web API. I chose Web API to create the services because it makes creation and consumption of HTTP services very easy. If you are new to Web API, checkout Web API content on official ASP.NET website.

Following are the ShoppingCartItem and ShoppingCart classes, these classes are used to define structure of each item and to operate on the current items on the cart respectively.

public class ShoppingCartItem
{
    public int ID { get; set; }
    public string Name { get; set; }
    public float Price { get; set; }
    public int Quantity { get; set; }
}


public class ShoppingCart
{
    static List<ShoppingCartItem> cartItems;

    static ShoppingCart()
    {
        cartItems = new List<ShoppingCartItem>()
        {
            new ShoppingCartItem(){ID=1,Name="Soap",Price=25,Quantity=5},
            new ShoppingCartItem(){ID=2,Name="Shaving cream",Price=30,Quantity=15},
            new ShoppingCartItem(){ID=3,Name="Shampoo",Price=100,Quantity=5}
        };
    }
 
    public void AddCartItem(ShoppingCartItem item)
    {
        int nextID = cartItems.Max(sci => sci.ID) + 1;
        item.ID = nextID;
        cartItems.Add(item);
    }

    public IEnumerable<ShoppingCartItem> GetAllItems()
    {
        return cartItems;
    }

    public void RemoveItem(int id)
    {
        cartItems.RemoveAll(sci => sci.ID == id);
    }
}

In the controller, we just need to invoke the methods defined in the ShoppingCart class. This makes the controller pretty straight forward. Following is the implementation:
public class ShoppingCartController : ApiController
{
    ShoppingCart cart;
 
    public ShoppingCartController()
    {
        cart = new ShoppingCart();
    }
 
    // GET api/<controller>
    public IEnumerable<ShoppingCartItem> Get()
    {
        return cart.GetAllItems();
    }
 
    // POST api/<controller>
    public void Post(ShoppingCartItem item)
    {
        cart.AddCartItem(item);
    }
 
    // DELETE api/<controller>/5
    public HttpResponseMessage Delete(int id)
    {
        cart.RemoveItem(id);
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
}

As we see, the URI templates to call each of these methods are specified in a comment above each method. For example, to call the get method to obtain all cart items, we will use the following logic:
$http.get('/api/shoppingCart/').success(function (data) {
     $scope.items = data;
    });

I am using the shorthand get method of http service here. We can obtain the same result using $http(options) as well. For the time being, I am placing the logic of AJAX calls in Controller to make the demo simple. We will move it into a module in another post. Following is the modified controller:
function ShoppingCartCtrl($scope, $http) {
 $scope.items = [];

 $scope.item = {};
 
 $scope.sortExpression = "Name";

 function refreshItems(){
  $http.get('/api/shoppingCart/').success(function (data) {
  $scope.items = data;
       });
 };
 
 $scope.addItem = function (item) {
  $http.post('/api/shoppingCart/', item).success(function(){
  refreshItems();
  });
  $scope.item = {};
                $scope.itemForm.$setPristine();
 };
 
 $scope.removeItem = function (id) {
  $http.delete('/api/shoppingCart/'+id).success(function(){
  refreshItems();
  });
 };
 
 $scope.mySortFunction = function(item) {
  if(isNaN(item[$scope.sortExpression]))
   return item[$scope.sortExpression];
  return parseInt(item[$scope.sortExpression]);
 };
 
 $scope.totalPrice = function(){
  var total = 0;
  for(count=0;count<$scope.items.length;count++){
   total += $scope.items[count].Price*$scope.items[count].Quantity;
  }
  return total;
 };
 
 $scope.name=/^[a-zA-Z ]*$/;
  
 $scope.integerval=/^\d*$/;

 refreshItems();
}

 Complete code of the sample is available on this github repo: AngularShoppingCart
I will be adding more code to this repo in the future.

Happy coding!

2 comments:

  1. Hello!
    i'm having this error:
    "Failed to load resource: net::ERR_CONNECTION_REFUSED"

    and my path is like this:

    apiPath: 'http://localhost/appCardapioWs/api/app_bebidaApi/'

    when I try this link on my browser, it works..

    What may I'm doing wrong?

    ReplyDelete
    Replies
    1. Adriano,
      I can't answer this question unless I see the code in action.

      Delete