Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Single Page Application using AngularJS and Web API and Responsive using Bootstrap.

0.00/5 (No votes)
20 Nov 2014 1  
This article describes the AngularJS JavaScript framework and shows how to use it to develop a Single Page Application.

Table of Contents

What is AngularJS?

AngularJS is a structural JavaScript framework to build a Single Page Application (SPA). AngularJS is a complete client-side framework which provides almost all the services such as data binding, templating, routing, validation, testing, dependency injection and resource for CRUD operations, etc.

Design Pattern used for AngularJS

AngularJS uses MVC design pattern to structure the code. In MVC, data and code are separate in three components, Model, View and Controller.

Model contains the application data. For example:

var products = [
    {'name': 'Product 1',
     'description': 'Description of Product 1'},
    {'name': 'Product 2',
     'description': 'Description of Product 2'},
    {'name': 'Product 3',
     'description': 'The 'Description of Product 3'}
  ];

View contains the HTML with declarative data binding:

<ul>
    <li ng-repeat="product in products">
      <span>{{product.name}}</span>
      <p>{{product.description}}</p>
    </li>
</ul>

Controller is used as a mediator between Model and View. It contains data model and event handler. For example:

productApp.controller('ProductListCtrl', function ($scope) {
  $scope.price=100;
  $scope.AddProduct= function(product)
  {
    //code goes here
  };
});

Two Way Data Binding in Angularjs

One of the powerful features of AngularJS is two way data binding. In two way data binding, if user changes the UI value, then AngularJS automatically updates the underlying data model. In the reverse way, if underlying data model is changed, then Angular automatically updates the UI. It reduces the code writing to update the DOM.

The following picture shows two way data binding:

Image 1

Routing

Using Routing, we can partition the Index page in multiple view templates and can bookmark the URL in browser for different view template. For routing, Angular uses its built in "ngRoute" module and $routeProvider provider. The configuration for routing for the sample project is shown below:

var productcatApp = angular.module('productcatApp', [
'ngRoute',
'productcatControllers',
'productcatServices'
]);
productcatApp.config(['$routeProvider',
function ($routeProvider) {
    $routeProvider.
    when('/products', {
        templateUrl: 'Home/ProductList',
        controller: 'ProductListCtrl'
    }).
    when('/products/:productId', {
        templateUrl: 'Home/ProductDetail',
        controller: 'ProductDetailCtrl'
    }).
    when('/productNew', {
        templateUrl: 'Home/ProductNew',
        controller: 'ProductNewCtrl'
    }).
    when('/productUpdate/:productId', {
        templateUrl: 'Home/ProductUpdate',
        controller: 'ProductUpdateCtrl'
    }).
    otherwise({
        redirectTo: '/products'
    });
}]);

For every route, there is a Web API URL to extract view template and a controller to bind data with the extracted template.

Sample Project With Description

Description: This sample project is about how to display, add, edit and delete product from a product list.

The database diagram from this sample project is shown below:

Image 2

Index Page

Index page is used like a master page and contains a container which is always updated with the called template.

<div id="contentWrapper">
    <div class="container">
        <div ng-view></div>
    </div>
</div>

When user routes to a new url, then the content of the div with Angular directive ng-view is replaced with the new HTML template.

The sample project performs the following steps.

Step 1: Shows the List of Products

Image 3

The HTML template to display the list of products is shown below. File ProductList.cshtml contains this template in server.

<div class="row">
    <div class="col-xs-6 col-sm-6 col-md-6 col-lg-6">
        <button class="btn btn-primary btn-lg btn-block" ng-click="newProduct()">New</button>
    </div>
</div>
<div class="row" ng-repeat="product in products">
    <div class="col-xs-6 col-sm-8 col-md-8 col-lg-8">
        <a href="#/products/{{product.id}}">{{product.name}}</a>
    </div>
    <div class="hidden-xs col-sm-1 col-md-1 col-lg-1">
        <a href="#/products/{{product.id}}"><img class="img-thumbnail img-responsive" 

          ng-src="{{product.imageUrl}}"/></a>
    </div>
    <div class="col-xs-3 col-sm-2 col-md-2 col-lg-2">
        <a class="btn btn-large btn-success" href="#/productUpdate/{{product.id}}">Update</a>
    </div>
    <div class="col-xs-3 col-sm-2 col-md-2 col-lg-2">
        <button class="btn btn-large btn-success" 

                ng-click="deleteProduct(product)">Delete</button>
    </div>
</div>

In the above template, ng-repeat="product in products" is used to loop the products list and {{product.name}} syntax is used for two way data binding. And class="col-xs-6 col-sm-6 col-md-6 col-lg-6" syntax is used for bootstrap.

The Routing part to call this template is:

when('/products', {
    templateUrl: 'Home/ProductList',
    controller: 'ProductListCtrl'
})

When url http://localhost/#/products is requested, then Angular calls an Ajax request to the Web API URL 'Home/ProductList' for a new HTML template and after return Angular bound the Controller 'ProductListCtrl' with the new template for data.

The Controller for this Template is:

var productcatControllers = angular.module('productcatControllers', []);
productcatControllers.controller('ProductListCtrl', ['$scope', '$routeParams', '$location', 
                                 '$route', 'productService',
function ($scope, $routeParams, $location, $route, productService) {
    productService.query(function (data) {
        $scope.products = data;
    });
    $scope.deleteProduct = function (product) {
        debugger;
        productService.delete({ id: product.id }, function () {
            $route.reload();
        });
    }
    $scope.newProduct = function () {
        $location.path('/productNew');
    }
}]);

Here, Angular Resource module is used to extract data from server and delete a product from server. Here, newProduct() function is used to redirect to the New Product add page.

The configuration for Resource module is:

var phonecatServices = angular.module('productcatServices', ['ngResource']);
phonecatServices.factory("productService", function ($resource) {
    return $resource(
        "/api/Product/:id",
        { id: "@id" },
        {
            "update": { method: "PUT" }

        }
    );
});

The above statement creates a service with name productService and passes a $resource service as a parameter which is used for database operations.

The server side Web API code is:

public HttpResponseMessage GetProducts()
        {
            var collection = db.Products.Select(x => new
            {
                id = x.id,
                name = x.name,
                imageUrl = x.imageUrl
            });
            var yourJson = new JavaScriptSerializer().Serialize(collection);
            var response = this.Request.CreateResponse(HttpStatusCode.OK);
            response.Content = new StringContent(yourJson, Encoding.UTF8, "application/json");
            return response;
        }

Step 2: Add a New Product

Image 4

ProductNew.cshtml page in server contains HTML template for this UI.

The Routing part to call this template is:

when('/productNew', {
    templateUrl: 'Home/ProductNew',
    controller: 'ProductNewCtrl'
})

The Controller for this Template is:

productcatControllers.controller('ProductNewCtrl', ['$scope', '$routeParams', '$location', 
                     'productService',
function ($scope, $routeParams, $location, productService) {
    $scope.product = { name: "", imageUrl: "", ProductDetail: { number: 0, price: 0.0, 
                       description: "", companyName: "" } };
    $scope.addNewProduct = function (product) {
        productService.save(product, function () {
            $location.path('/products');
        });
    }
    $scope.cancelNewProduct = function () {
        $location.path('/products');
    }
}]);

In the about controller, save function of productService service is used to save a product in database and after save, it redirects to the product list page.

The server side Web API code is:

public HttpResponseMessage PostProduct(Product product)
        {
            if (ModelState.IsValid)
            {
                db.Products.Add(product);
                db.ProductDetails.Add(product.ProductDetail);
                db.SaveChanges();
                return Request.CreateResponse(HttpStatusCode.OK);
            }
            else
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
        }

Step 3: Edit a Product

Image 5

ProductUpdate.cshtml page in server contains HTML template for this UI.

The Routing part to call this template is:

when('/productUpdate/:productId', {
    templateUrl: 'Home/ProductUpdate',
    controller: 'ProductUpdateCtrl'
})

The Controller for this Template is:

productcatControllers.controller('ProductUpdateCtrl', ['$scope', '$routeParams', 
                                 '$location', 'productService',
function ($scope, $routeParams, $location, productService) {
    productService.get({ id: $routeParams.productId }, function (data) {
        $scope.product = data;
    });
    $scope.updateProduct = function (product) {
        var post = productService.get({}, { id: product.id }, function (data) {
            debugger;
            post.name = product.name;
            post.imageUrl = product.imageUrl;
            post.ProductDetail.number = product.ProductDetail.number;
            post.ProductDetail.price = product.ProductDetail.price;
            post.ProductDetail.description = product.ProductDetail.description;
            post.ProductDetail.companyName = product.ProductDetail.companyName;
            productService.update(post, function () {
                $location.path('/products');
            });
        });
    }
    $scope.cancelUpdateProduct = function () {
        $location.path('/products');
    }
}]);

In the about controller, update function of productService service is used to update a product in database and after update it redirect to the product list page.

The server side Web API code is:

public HttpResponseMessage PutProduct(int id, Product product)
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
            if (id != product.id)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }
            Product productEntity = 
                    db.Products.Where(p => p.id == product.id).FirstOrDefault();
            productEntity.name = product.name;
            productEntity.imageUrl = product.imageUrl;
            productEntity.ProductDetail.number = product.ProductDetail.number;
            productEntity.ProductDetail.price = product.ProductDetail.price;
            productEntity.ProductDetail.description=product.ProductDetail.description;
            productEntity.ProductDetail.companyName = product.ProductDetail.companyName;
            db.Entry(productEntity).State = EntityState.Modified;
            try
            {
                db.SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex)
            {
                return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
            }
            return Request.CreateResponse(HttpStatusCode.OK);
        }

Step 4: Display the Product Details

Image 6

ProductDetail.cshtml page in server contains HTML template for this UI.

The Routing part to call this template is:

when('/products/:productId', {
    templateUrl: 'Home/ProductDetail',
    controller: 'ProductDetailCtrl'
})

The Controller for this Template is:

productcatControllers.controller('ProductDetailCtrl', ['$scope', '$routeParams', 
                                 '$location', 'productService',
function ($scope, $routeParams, $location, productService) {
    productService.get({ id: $routeParams.productId }, function (data) {
        $scope.product = data;
    });
    $scope.backToProduct = function () {
        $location.path('/products');
    }
}]);

In the about controller, get function of productService service is used to extract a product by id from database and assign the data with product Model.

The server side Web API code is:

public HttpResponseMessage GetProduct(int id)
{
    var product = db.Products.Include("ProductDetail").Where(p => p.id == id).Select(x => new
    {
        id = x.id,
        name = x.name,
        imageUrl = x.imageUrl,
        ProductDetail = new { id = x.ProductDetail.id, number = x.ProductDetail.number, 
                        price = x.ProductDetail.price, 
                        description = x.ProductDetail.description,
                        companyName = x.ProductDetail.companyName }
    }).FirstOrDefault();
    var json = new JavaScriptSerializer().Serialize(product);
    var response = this.Request.CreateResponse(HttpStatusCode.OK);
    response.Content = new StringContent(json, Encoding.UTF8, "application/json");
    return response;
}

Conclusion

In conclusion, I can say, now a days, Angular is a popular JavaScript framework to develop a Single Page Application. Please download the attached zip file for the sample project. It needs VS2012 and SQL Server 2008 to run.

History

  • 21st November, 2014: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here