Click here to Skip to main content
15,216,450 members

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

Rate this:
4.81 (23 votes)
Please Sign up or sign in to vote.
4.81 (23 votes)
20 Nov 2014CPOL
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Khademul Basher
Founder http://softwarelandmarks.com/
Bangladesh Bangladesh
I am in Software Development for more than 12 years. I am expert on Microsoft Platform for Web Forms, MVC, MVC Core, Web API, Desktop App, PHP etc. I am also expert on jQuery, AngularJS, Bootstrap, Font Awesome, Telerik UI, Kendo UI etc. I know BackboneJS, KnockoutJS also. I am an article writer. I have many articles in CodeProject.

Email: khademulbasher@gmail.com

Comments and Discussions

 
Questionwant step by step explanation. Pin
Member 1304972214-Mar-17 4:27
MemberMember 1304972214-Mar-17 4:27 
QuestionVery cool code sample about Bootstrap/AngularJS Pin
Pham Dinh Truong19-Oct-16 22:15
professionalPham Dinh Truong19-Oct-16 22:15 
BugProductInfo-noexe.zip Pin
aoinal12-Jun-16 23:17
Memberaoinal12-Jun-16 23:17 
QuestionMVC and Design Patterns Pin
tatran.eu@gmail.com24-May-15 11:40
Membertatran.eu@gmail.com24-May-15 11:40 
GeneralMy vote of 5 Pin
Accioly26-Nov-14 15:55
MemberAccioly26-Nov-14 15:55 
SuggestionYou just need to specify the smallest grid Pin
rtpHarry26-Nov-14 11:33
professionalrtpHarry26-Nov-14 11:33 
GeneralMy vote of 5 Pin
Humayun Kabir Mamun21-Nov-14 1:08
MemberHumayun Kabir Mamun21-Nov-14 1:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Article
Posted 20 Nov 2014

Stats

79.9K views
61 bookmarked