Using AngularJS to consume WebAPI service in MVC4 project

AngularJS is a very powerful javascript framework with very big set of features like letting you extend HTML syntax to express your application components, two way data binding between your DOM and your  model, dependancy injection and inversion of control in the browser! and it makes testing your javascript code very easy.

In this article I will show you how easy it is to setup your application to use AngularJS and as a start we will use it to consume the WebApi service on the server.

The Solution:
So we have an MVC4 project with a WebAPI controller that handles GET, PUT operations on a group of blog posts. the code for this controller looks like this:

using System.Collections.Generic;
using System.Linq;
using Blog13.Data;

namespace Blog13.Web.Services.Controllers
{
    public class PostsViewModel
    {
        public string Title { get; set; }
        public string Body { get; set; }
        public int Id { get; set; }
        public string AuthorName { get; set; }
        public string[] Tags { get; set; }
    }

    public class PostsController : BlogBaseApiController
    {
        private readonly EfRepository _repository;

        public PostsController()
        {
            _repository = new EfRepository(new EfDbContext());
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                _repository.Dispose();
            }
            base.Dispose(disposing);
        }

        // GET api/Posts
        public IEnumerable<PostsViewModel> Get()
        {
            System.Threading.Thread.Sleep(5000); //only for testing loading time..remove in production code
            return _repository.GetPosts().Select(obj => new PostsViewModel()
            {
                AuthorName =  obj.Author.Name,
                Title =  obj.Title,
                Id =  obj.Id,
                Body =  obj.Body,
                Tags =  obj.Tags.Select(tag => tag.Value).ToArray()
            });
        }

        // PUT api/Posts
        public void Put(IEnumerable<PostsViewModel> posts)
        {
            System.Threading.Thread.Sleep(5000); //only for testing loading time..remove in production code
            //TODO: update posts
        }

    }
}

At this point if we used Fiddler to execute a GET request to /api/posts/ we will have a JSON result as in this image:
Screen Shot 2013-02-03 at 3.16.34 PM

Adding AngularJS
In master page or like in my case _layout.cshtml (as I’m using Razor) you will have to make two changes:

  1. In html tag add ng-app attribute which indicate to the AngularJS framework that this is an AngularJS application
    <!DOCTYPE html>
    <html ng-app>
    <head>
    
  2. Inside head element add a script entry for the AngularJS file
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js"></script>
    

Using AngularJS
I decided to load these posts in my home index view so this is the code that exists in my Views/Home/Index.cshtml file:

<script src="~/Scripts/PostsController.js"></script>
<div ng-controller="PostsController">
    <strong class="error">{{ error }}</strong>
    <strong ng-show="loading">loading..</strong>
    <div ng-repeat="post in posts">
        <strong ng-hide="editMode">{{ post.Title }}</strong>
        <input ng-show="editMode" type="text" ng-model="post.Title"/>
        <p ng-hide="editMode">{{ post.Body }}</p>
        <p ng-show="editMode"><textarea ng-model="post.Body"></textarea></p>
        <span ng-repeat="tag in post.Tags">
            <span>{{ tag }} </span>
        </span>
        <p>Author: {{ post.AuthorName }}</p>
        <hr/>
    </div>
    <div ng-show="posts.length > 0">
        <a ng-click="toggleEdit()" href="javascript:;">Edit</a>
        <a ng-click="save()" href="javascript:;">Save</a>
    </div>
</div>

As you can see, the most notable thing is using MVC pattern here so top most div in this component declares this attribute: ng-controller="PostsController" this means that the framework will use the controller PostsController to handle this portion of the page (the view).

PostsController itself is declared in the javascript file that is added on the first line in a script element with the src="~/Scripts/PostsController.js" So lets have a look at this file:

function PostsController($scope, $http) {

    $scope.loading = true;
    $scope.editMode = false;

    $http.get('/api/posts/').success(function (data) {
        $scope.posts = data;
        $scope.loading = false;
    })
    .error(function () {
        $scope.error = "An Error has occured while loading posts!";
        $scope.loading = false;
    });

    $scope.toggleEdit = function() {
        $scope.editMode = !$scope.editMode;
    };

    $scope.save = function() {
        $http.put('/api/posts/', $scope.posts).success(function (data) {
            alert("Saved Successfully!!");
        }).error(function (data) {
            $scope.error = "An Error has occured while Saving posts! " + data;
            $scope.loading = false;
        });
    };

}

controller code is very easy and self explaining, its just a function, the name of the function is the name of the controller that is used in the markup, the function takes two parameters the first one is the most important $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 <span>{{ foo }}</span> so I will have the string “bar” in my span after binding.

The other parameter $http gets resolved for you using the AngularJS DI framework to The $http service in core Angular that facilitates communication with the remote HTTP servers via browser’s XMLHttpRequest object or via JSONP. Its usage is very self explanatory in the previous code.

Running the application
So lets see what these two bits of codes did..when we start this application we will see a loading indicator
Screen Shot 2013-02-03 at 4.10.01 PM
after a while is disappears when data is loaded, then the loaded data is bound and appears to the viewer
Screen Shot 2013-02-03 at 4.10.08 PM
When a user clicks on Edit link the view shows editable text boxes instead of labels
Screen Shot 2013-02-03 at 4.10.20 PM
clicking save will post the modified data back to the server using a PUT http verb. I have added a breakpoint in the Put controller action and this is the list of modified posts just as expected
Screen Shot 2013-02-03 at 4.17.24 PM
pretty neat! so enjoy it!!

Advertisements
This entry was posted in Software and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s