Decouple your UI logic from backend logic using AngularJS & Web API

If we step back in history about five years we’d realise that the best web technologies available for APS.NET developers were Web Forms and MVC frameworks. Those technologies have offered a great deal of rapid development and better user experience to consumers. Therefore, many businesses have adopted them to build their business tools and web applications. But to cope with the market demand for supporting web users on various devices such as desktops, mobiles, tablets etc… the web technology has to adapt to those demands and it has to be flexible enough to accommodate the change quickly when needed.
In technology we have learnt that system decoupling is the best mechanism to allow change and apply system maintenance without having to rewrite the entire software. As a web developer, it was a dream for me to completely decouple the UI logic from the backend using a structural language. So if I need to use a different javascript framework for UI or change my backend framework or even the programming language for my current application, I have the flexibility to do so without having to rewrite the entire application. I struggled to achieve this with ASP.NET web forms or MVC but when I came across AngularJS it was like a dream come true.
In this article I will show you how you can simply build pure “HTML” pages that use AngularJS for data binding and Restangular to consume data served by a RESTful ASP.NET Web API.

The AngularJS & Web API Implementation

We are going to build a single page application that can add, edit, read and delete user details.
Create MVC5 project with a Web API controller called “user” that handles CRUD operations for user details. The code for this controller is like this…

namespace UserManagement.Site.Controllers
{
    [RoutePrefix("api/users")]
    public class UserController : ApiController
    {
        // GET: /api/users
        [HttpGet]
        [Route("")]
        public IHttpActionResult Get()
        {
            var result = GetUsers();
            return Ok(result);
        }
        // GET: /api/users/{id}
        [HttpGet]
        [Route("{id}", Name = "GetUserById")]
        public IHttpActionResult GetById(int id)
        {
            var result = new User();
            return Ok(result);
        }
        // POST: /api/users
        [HttpPost]
        [Route("")]
        public IHttpActionResult Create(User model)
        {
            return CreatedAtRoute("GetUSerById", new {id = model.Id}, model);
        }
        // PUT: /api/users/{id}
        [HttpPut]
        [Route("{id}")]
        public IHttpActionResult Update(string id, User model)
        {
            return Ok(model);
        }
        // DELETE: /api/users/{id}
        [HttpDelete]
        [Route("{id}")]
        public IHttpActionResult Delete(string id)
        {
            return Ok();
        }
        private List GetUsers()
        {
            return new List
            {
                new User { Id = 1 , DisplayName = "Ahmed"},
                new User { Id = 2 , DisplayName = "John"},
                new User { Id = 3 , DisplayName = "Tom"},
                new User { Id = 4 , DisplayName = "Mark"},
            };
        }
    }
}

At this point we can use Fiddler to execute a GET request to /api/users/ we will have a JSON result of the users list.

Adding AngularJS

In master page or like in my case Index.cshtml (as I’m using Razor only to bundle my scripts and css files) you will have to make two changes:
Add script entries for AnguralJS, Restangular and other required scripts, as follows

@Scripts.Render("~/Scripts/app")

In HTML tag add ng-app attribute which indicates to the AngularJS framework that this is an AngularJS application



Using AngularJS

In the main content part of the HTML, add data-ng-view attribute (similar to in Razor) by this directive angular know that, this is the place where template will be injected.


In my application route I have set my home template and controller as follows:

$routeProvider.when('/',
{
   controller: 'HomeController',
   templateUrl: '/scripts/app/user/home.html'
});

Routing, application configs and modules registration are defined inside Scripts/app/app.js file.
HomeController is the main controller that handles all the logic for the home template when the application loads, so lets have a look at it:

angular.module("app.user", ['app.user.factory'])
    .controller("HomeController", ['$scope', '$modal', '$location', 'GetUsersFactory', 'UserFactory',
         function ($scope, $modal, $location, getUsersFactory, userFactory) {
             $scope.users = [];
             $scope.data = {
                 showError: false
             };
             getUsersFactory.get().then(function (data) {
                 $scope.users = data;
             }, function (error) {
                 if (error.status == 404) {
                     return $location.path('/error/not-found-restaurant');
                 }
                 if (error.status != 401) {
                     return $location.path('/error');
                 }
             });
             $scope.deleteUser = function (user) {
                 user.remove().then(function () {
                         var index = $scope.users.indexOf(user);
                         $scope.users.splice(index, 1);
                     }, function (error) {
                         $scope.data.showError = true;
                     });
             };
             $scope.addUser = function () {
                 $scope.data.showError = false;
                 $modal.open({
                     templateUrl: '/scripts/app/user/addUserModal.html',
                     controller: "addUserModalController",
                     resolve: {
                         model: function () {
                             return userFactory.create();
                         },
                         users: function () {
                             return $scope.users;
                         }
                     }
                 });
             };
             $scope.editUser = function (user) {
                 $scope.data.showUsernameUniqueError = false;
                 $scope.data.showError = false;
                 var modalInstance = $modal.open({
                     templateUrl: '/scripts/app/user/editUserModal.html',
                     controller: "editUserModalController",
                     size: "small",
                     resolve: {
                         model: function () {
                             $scope.original = user;
                             return user;
                         },
                         users: function () {
                             return $scope.users;
                         }
                     }
                 });
                 modalInstance.result.then(function (userItem) {
                     userItem.put().then(function (editedUser) {
                         angular.copy(editedUser, $scope.original);
                     }, function (error) {
                         $scope.data.showError = true;
                     });
                 });
             };
         }]);

The controller code is very easy and self explanatory, it’s just a function. The name of the function is the name of the controller that is used in the application route, the function takes a number of parameters. The first one is $scope. This is the object that is getting bound to the DOM for example if in this function I set $scope.foo = “bar”; in markup I can use this binding expression {{ foo }} so I will have the string “bar” in my span after binding.
Another thing to note here is that we are injecting app.user.factory module into the controller module, this module holds the initialisation for Restangular object. “Restangular is an AngularJS service that simplifies common GET, POST, DELETE, and UPDATE requests with a minimum of client code. It’s a perfect fit for any WebApp that consumes data from a RESTful API.”
So let’s look at app.user.factory in the following script:

angular.module("app.user.factory", [])
 .factory('UserFactory', ['Restangular',
        function (restangular) {
            var service = {
                create: function () {
                    var user = {
                        id: null,
                        displayName: "",
                        mobileContact: "",
                        post: function () {
                            return restangular.all("users").post(this);
                        }
                    };
                    return user;
                }
            };
            return service;
        }])
.factory('GetUsersFactory', ['Restangular',
        function (restangular) {
            var service = {
                get: function () {
                    return restangular.all('users').getList().then(function (data) {
                        return data;
                    });
                }
            };
            return service;
        }]);

In the code above I’m defining my user resource and creating main Restangular object. There are three ways of creating a main Restangular object. The first one and most common one is by stating the main route of all requests. The second one is by stating the main route and object of all requests.

// Only stating main route
Restangular.all(users)
// Stating main object
Restangular.one('users', userData)
// Gets a list of all of those accounts
Restangular.several('users', userData1, userData2, userData3);

In my case I’m using restangular.all(“users”).post(this) which is performing a post request on api/users endpoint to create the user. Similar to restangular.all(‘users’).getList() which is a get request on api/users returning all list of users.

Running the application

When running the application you will be presented with a list of users displayed in an HTML table using ngRepeat. When the application loads you will be able to perform basic CRUD operations on the user resource by calling the Web API endpoints defined in the HomeController.
user-management-app
By doing this, we have no dependencies between UI and backend logics, no shared models nor UI controls. The user interface layer is purely HTML, javascript, css and backend layer is purely c#.
Pretty neat – enjoy it!
The full source code of the application is available on GitHub here: https://github.com/justeat/AngularJSWebAPI.Experiment.git

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