Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Getting Started with AngularJS - Part II

4.81/5 (8 votes)
27 Oct 2015CPOL4 min read 17.1K   316  
This article will demonstrate how to get started developing websites with AngularJS. Connect with server database by http methods.

Introduction

In the previous article Getting Started with AngularJS - Part I, we have seen a CRUD example with in-memory array in AngularJS. In this article, I will continue with the same example but now we will use server-side data-storage in our application. For the purpose of this article, I have used the embedded database SQL Server Compact Edition. And I used asp.net-webapi as the mechanism for communicating with server side.

Background

Microsoft SQL Server Compact (SQL CE) is a compact relational database produced by Microsoft for applications that run on mobile devices and desktops. It shares a common API with the other Microsoft SQL Server editions. It also includes ADO.NET providers for data access using ADO.NET APIs, as well as support for LINQ and Entity Framework. SQL CE databases reside in a single .sdf file, which can be up to 4 GB in size. The .sdf file can simply be copied to the destination system for deployment. It also supports the DataDirectories, applications using an SQL CE database need not specify the entire path to an .sdf file in the ADO.NET connection string, rather it can be specified as |DataDirectory|\<database_name>.sdf.

If you have not already installed it, then you can download it from Microsoft SQL Server Compact 4.0.

ASP.NET Web API support enables you to easily create powerful Web APIs that can be accessed from a broad range of clients (ranging from browsers using JavaScript, to native apps on any mobile/client platform). For more details and tutorials on ASP.NET WebAPI, you can visit this link.

Using the Code

Let's start with the code, first I changed the directory structure for this application. You will see the application structure like this:

Image 1

And therefore we have to change the files references in index.html page.

HTML
<link href="client/assets/css/main.css" rel="stylesheet" />
<link href="client/assets/css/menu.css" rel="stylesheet" />

<!-- external libs -->
<script type="text/javascript"
src="client/assets/libs/angular.js"></script>
<script type="text/javascript"
src="client/assets/libs/angular-route.js"></script>

<!-- root -->
<script src="client/ap/app.module.js"></script>
<script src="client/ap/app.routes.js"></script>

<!-- services -->
<script src="client/ap/services/productFactory.js"></script>
<script src="client/ap/services/categoryFactory.js"></script>

<!-- controllers -->
<script src="client/ap/controllers/productController.js"></script>
<script src="client/ap/controllers/categoryController.js"></script>

<!-- app -->
<script src="client/ap/app.js"></script>

Database

Since we are using SQL Compact Edition for this post, let's create two tables Product and Category with the following schema, and populate sample data.

Image 2

Image 3

ASP.NET-WebAPI

We are already with our database, now we will develop WebAPI to communicate with server. As you might have noticed, I am using ASP.NET website template. So all we need to do is write data access code and add API controllers. Here, we have to do 3 things:

  1. Create Entity Framework Model for our database.
  2. Create two view-model classes, ProductView and CategoryView.
  3. Now we can move to the actual WebAPI part, create two controllers - ProductController and CategoryController.

You will find the code for controllers and all other things in the attached source code, look at this code listing you need to put in Global.asax to enable WebAPI routing.

C#
protected void Application_Start(object sender, EventArgs e)
    {
        RouteTable.Routes.MapHttpRoute(
                name: "ActionApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
    }

Now our WebAPI is ready to get called from any client.

JavaScript / Angular Factory

Since we used Angular Factories in the previous article, we only have to change that part to call server data. Instead of using in-memory array of products or categories, we now make a call to WebAPI to get data from server-side. Here is the update code listing for productFactory.

C#
// Define Factory
demoApp.factory('productFactory', function ($http) {
    var products = [];
    var categories = [];

    var factory = {};
    factory.getProducts = function () {

        $http.get('api/Product/Get').
            success(function (data, status, headers, config) {
                
                data = data.substring(1, data.length);
                data = data.substring(0, data.length - 1);
                data = data.replace(/\\/g, "");

                var jsonStringFormatted = data;
                
                var objectArray = JSON.parse(jsonStringFormatted);
                var obj;

                products.length = 0;
                for (i = 0; i < objectArray.length; i++) {

                    obj = factory.cloneProduct(objectArray[i]);
                    products.push(obj);
                }
                console.log("get products list - success");
            }).
            error(function (data, status, headers, config) {
                // log error
                console.log(status);
            });

        return products;
    };

    factory.getCategories = function () {

        $http.get('api/Category/Get').
            success(function (data, status, headers, config) {

                data = data.substring(1, data.length);
                data = data.substring(0, data.length - 1);
                data = data.replace(/\\/g, "");

                var jsonStringFormatted = data;

                var objectArray = JSON.parse(jsonStringFormatted);
                var obj;

                categories.length = 0;
                for (i = 0; i < objectArray.length; i++) {

                    obj = factory.cloneCategory(objectArray[i]);
                    categories.push(obj);
                }
            }).
            error(function (data, status, headers, config) {
                // log error
                console.log(status);
            });

        return categories;
    };

    factory.loadProductById = function (id) {
        var objFound;

        for (var i = 0; i < products.length; i++) {
            if (products[i].Id == id) {
                objFound = products[i];
                break;
            }
        }

        return objFound;
    };

    factory.getCategoryById = function (id) {
        var objFound;

        for (var i = 0; i < categories.length; i++) {
            if (categories[i].Id == id) {
                objFound = categories[i];
                break;
            }
        }

        return objFound;
    }

    factory.saveProduct = function (product) {
        
        var config = {
            //headers: 'application/x-www-form-urlencoded',
            headers: { 'Content-Type': 'application/json' }
        }

        $http.post('api/Product/PostProduct', product, config)
            .then(
                function (response, status, headers, config) {
                    console.log('PostProduct success: ' + product.Id); 
                },
                function (response, status, headers, config) {
                    console.log('PostProduct failed.', response, status, headers); 
                }
            );
    };

    factory.cloneProduct = function (obj) {

        tempObj = {};
        tempObj.Id = obj.Id;
        tempObj.ProductCode = obj.ProductCode;
        tempObj.ProductName = obj.ProductName;
        tempObj.Description = obj.Description;
        tempObj.CategoryID = obj.CategoryID;
        tempObj.CategoryName = obj.CategoryName;

        return tempObj;
    };

    factory.cloneCategory = function (obj) {

        tempObj = {};
        tempObj.Id = obj.Id;
        tempObj.CategoryCode = obj.CategoryCode;
        tempObj.CategoryName = obj.CategoryName;

        return tempObj;
    };

    factory.deleteProduct = function (id) {

        var params = "productID=" + id;

        $http.delete('api/Product/DeleteProduct?' + params)
        .then(
            function (response, status, headers) {
                console.log('DeleteProduct success: ');
            },
            function (response, status, headers) {
                console.log('DeleteProduct failed.', response, status, headers);
            }
        );
    };

    return factory;
});

Here, you see that getProduts() function makes a http get request to the WebAPI's ProductController by invoking $http.get('api/Product/Get') function. $hhtp.get() will accept two callback functions success callback and error callback, for which you can write appropriate code handling you want. Similarly, we have used $hhtp.post() and $hhtp.delete() for posting and deleting product respectively.

Points of Interest

We are done with our CRUD example with AngularJS, with server-side data-storage. I discussed only the code part related to one entity Product, for Category you will also find similar code listing in the downloaded sample.

One thing I experienced while working on this article, you might also find interesting. Before I was using an older version of SQL Compact Edition (3.5.8080.0) and I created my database file with that version, and wrote my C# code using a higher version Framework 4. When I tried to access data from that file, I got an error which I fixed by simply calling a helper class's method SqlCeEngine.Upgrade(). This I didn't remove from the code listing, you will find these two lines of code as commented in the ProductController's GetAll method.

I hope you also enjoyed this article and got something out of it. I appreciate your feedback/comments or any improvements you want to suggest in this topic, to help in making the article better and helpful for others.

History

  • 27 October 2015: Posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)