In the first part of our Project Tracking Website Project Tracking Website using AngularJS and ASP.NET Web API, we did a brief overview of why do we need AngularJS, what is AngularJS and an example of using AngularJS. In the 2nd part of this series, we built some REST based services using ASP.NET Web API. This article is part III of a series of articles on how to build interactive web sites using ASP.NET Web API and the popular client side JavaScript library called AngularJS. This AngularJS series has been reviewed by Ravi Kiran.
In this article, we will take a closer look at AngularJS Controllers. We will use AngularJS controllers to build the model for our Project Tracking website. Initially we will build the models for our project with some static data and later we will replace them with calls to HTTP Services. We will also look at how to design Views to perform different operations as per the user's requests.
AngularJS Controller
In an Angular JS application, everything starts with the Controller. The Controller communicates with the model and bundles up what is needed for the view. So the controller is responsible to build the ViewModel. You can create multiple controllers for your application. Controller also provides command methods that can be called from the view on certain events.
Before adding controllers into our project, we will first add an AngularJS Module with the name app.js into our Scripts folder and write the following code:
AngularJS Module
A module in AngularJS is like a container. It can contain different parts of your application like Controllers, Services, Filters, and Directives. You can have one or more than one Modules depending on how complex your application is. There are a couple of advantages of using Modules in AngularJS –
- The bootstrapping of the application can be specified by module declaratively and hence they are easy to understand.
- Modules are reusable.
- Modules help in keeping the code cleaner. We can achieve better separation of concerns by creating a module for every domain aspect of the application.
- Modules can be loaded in any order or even parallel because they delay execution.
- Testing is easier and faster as you need to load only those modules which are needed.
To build the controller into our Project Tracking website, we will add a JavaScript file in our Controllers folder with the name HomeController. We will write some code in our JavaScript file –
(function () {
var HomeController = function ($scope) {
$scope.Message = "WelCome to Online Project Tracking Web site";
};
app.controller("HomeController", HomeController);
}());
A controller is just a function which will be invoked by AngularJS in HTML. We can make use of the above declared controller into our HTML page using an Angular directive ng-controller. We can provide a name to our controller to identify each controller uniquely. We will be creating multiple controllers for our website.
Now let’s try using this controller into our Home.html page. First add ng-app directive to our <HTML> tag and then add ng-controller directive in our <body> tag as shown below:
AngularJS will read the ng-app directive from the HTML page and bootstrap the Angular module. Then it will look for other directives/expressions. In our case, AngularJS will read the ng-controller directive. AngularJS controller takes the $scope parameter. $ is a special sign used for convention in AngularJS. Anything that starts with $ is a component of AngularJS which comes out-of-box. In HomeController, we have passed the $scope parameter. We attach the models to $scope. Angular now will look for CompanyName associated with $scope object. Include the HomeControllers.js file reference into our Home.html.
We will now use CompanyName property in our HTML. Let’s find the Anchor tag for our website title and change the code as shown here:
<a class="navbar-brand" href="..\Home.html">{{CompanyName}}</a>
The output is as follows:
Now let’s add EmployeesController into our Controllers folder and add the following code in our EmployeesController.js file –
(function () {
var EmployeesController = function ($scope) {
var employees = {
employeeName: "John Richard",
designation: "Project Manager",
contactNo: "+333 3888389",
eMailID: "john@projects.com",
skillSets: "ASP.NET, ASP.NET MVC"
};
$scope.Title = "Employee Details Page";
$scope.Employees = employees;
};
app.controller("EmployeesController", EmployeesController);
}());
In the above code, we are creating employees object and passing it as a model to the $scope object with the name Employees. We are also adding the controller into AngularJS Module which we have declared in the above steps. See the first figure. The above function is a Self-Executing Anonymous Function [SEF] or, Immediately Invoked Function Expression (IIFE). An IIFE is a function that is immediately defined and then invoked. Since JavaScript has a function scope, IIFE lets you create a ‘private scope’ which is safe from outside tampering. This separates your variables and other code from the global scope. When we add the parantheses () at the end of the function, it executes immediately. Now whatever variables and functions we have defined in this function, are not available to the code outside of it. Now we will add an EmployeeDetails.html page into our Employees folder. Design the Employees.html page as shown here:
<!DOCTYPE html>
<html lang="en" ng-app="ProjectTrackingModule">
<head>
<title>Employee Details</title>
<script src="../Scripts/jquery-2.1.0.min.js"></script>
<link href="../CSS/amelia.bootstrap.min.css" rel="stylesheet" />
<link href="../CSS/Site.css" rel="stylesheet" />
<script src="../Scripts/angular.min.js">
</script>
<script src="../Scripts/bootstrap.min.js">
</script>
<script src="../Scripts/app.js">
</script>
<script src="../Controllers/EmployeesController.js"></script>
</head>
<body ng-controller="EmployeesController">
<h1>{{Title}}</h1>
<p>Employee Name - {{Employees.employeeName}}</p>
<p>Designation - {{Employees.designation}}</p>
<p>Contact No. - {{Employees.contactNo}}</p>
<p>EMail ID - {{Employees.eMailID}}</p>
<p>Skill Sets - {{Employees.skillSets}}</p>
</body>
</html>
In the above HTML code, we have initialized Angular with ng-app directive which refers to our module “ProjectTrackingModule”. We have added EmployeesController with the help of ng-controller directive into our <body> tag. Then we have used the employees object which is associated with $scope object of Angular with the help of binding expression. Here’s the output of the above HTML code.
So far, the data which we used in this demo is static. We will try fetching the data from the database which we created in the first part of this series. For this, we will be fetching the HTTP services which we defined in article Building Services using ASP.NET Web APIs.
To fetch the HTTP services into AngularJS Controller, we will have to inject the $http service into our controller. As mentioned before, $ sign refers to AngularJS components and services. $http is a built-in service in AngularJS which helps in calling HTTP services. It provides HTTP methods like – GET, POST, PUT and DELETE to perform CRUD operations against the service loaded on some web server.
Let’s change the code in our EmployeesController.
(function () {
var EmployeesController = function ($scope,$http) {
var employees = function (serviceResp) {
$scope.Employees=serviceResp.data;
};
var errorDetails = function (serviceResp) {
$scope.Error="Something went wrong ??";
};
$http.get("http://localhost:2464/api/ptemployees")
.then(employees,errorDetails);
$scope.Title = "Employee Details Page";
};
app.controller("EmployeesController", EmployeesController);
}());
In the above code, we are using get() method of the $http service. This method does not return the data immediately because it performs the operation asynchronously. The get() method returns a promise.
A promise is an object which gives the access to the result of the asynchronous task, when it completes. The code consuming a promise can then use the result or handle the errors based on pass or fail case of the promise respectively. We can make use of the then method to fetch the response from the get() method. In our above code, we have created two functions. The first function employees assigns data of the result to Employees array. Also if something goes wrong, we can call the errorDetails() function to track the errors or log the error. In the above code, when the call is successful, we are calling the employee() function and when the call is unsuccessful, we are calling the errorDetails() function.
Run your Employee.html page and you should see the following output:
Now let’s redesign the EmployeeDetails.html page. To start with, we will modify the EmployeeDetails.html page to display the data in a tabular format. Instead of using <p> tag, I have added a table with CSS Bootstrap styling. The code is shown below –
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<td>
Employee ID
</td>
<td>
Employee Name
</td>
<td>
Designation
</td>
<td>
Contact No.
</td>
<td>
EMailID
</td>
<td>
Skill Sets
</td>
</tr>
</thead>
<tbody>
<tr class="success" ng-repeat="Employee in Employees">
<td>
{{Employee.employeeID}}
</td>
<td>
{{Employee.employeeName}}
</td>
<td>
{{Employee.designation}}
</td>
<td>
{{Employee.contactNo}}
</td>
<td>
{{Employee.eMailID}}
</td>
<td>
{{Employee.skillSets}}
</td>
</tr>
</tbody>
</table>
The output is as follows:
Now we will add ProjectsController.js into our Controllers folder.
ProjectsController.js –
(function () {
var ProjectsController = function ($scope, $http) {
var projects = function (serviceResp) {
$scope.Projects = serviceResp.data;
};
var errorDetails = function (serviceResp) {
$scope.Error = "Something went wrong ??";
};
$http.get("http://localhost:2464/api/ptprojects/1")
.then(projects, errorDetails);
$scope.Title = "Project Details Page";
};
app.controller("ProjectsController", ProjectsController);
}());
This is the same code which we wrote in EmployeesController.js file. We will now add an HTML page into the ProjectManagement folder with the name ProjectDetails.html and design the page as shown here –
ProjectDetails.html –
<!DOCTYPE html>
<html lang="en" ng-app="ProjectTrackingModule">
<head>
<title>Project Details</title>
<script src="../Scripts/jquery-2.1.0.min.js">
</script>
<link href="../CSS/amelia.bootstrap.min.css" rel="stylesheet" />
<link href="../CSS/Site.css" rel="stylesheet" />
<script src="../Scripts/angular.min.js">
</script>
<script src="../Scripts/bootstrap.min.js">
</script>
<script src="../Scripts/app.js">
</script>
<script src="../Controllers/ProjectsController.js"></script>
</head>
<body ng-controller="ProjectsController">
<h1>{{Title}}</h1>
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<td>
Project ID
</td>
<td>
Project Name
</td>
<td>
Start Date
</td>
<td>
End Date
</td>
<td>
Client Name
</td>
</tr>
</thead>
<tbody>
<tr class="success">
<td>
{{Projects.projectID}}
</td>
<td>
{{Projects.projectName}}
</td>
<td>
{{Projects.startDate}}
</td>
<td>
{{Projects.endDate}}
</td>
<td>
{{Projects.clientName}}
</td>
</tr>
</tbody>
</table>
</body>
</html>
The output is shown here:
Now add a controller for User Stories into our Controllers folder and write the following JavaScript code in the UserStoriesController.js file –
(function () {
var UserStoriesController = function ($scope, $http) {
var userStories = function (serviceResp) {
$scope.Stories = serviceResp.data;
};
var errorDetails = function (serviceResp) {
$scope.Error = "Something went wrong ??";
};
$http.get("http://localhost:2464/api/ptuserstories/1")
.then(userStories, errorDetails);
$scope.Title = "User Stories Page";
};
app.controller("UserStoriesController", UserStoriesController);
}());
We will add UserStoryDetails.html page into the UserStory folder. The UserStoryDetails.html page code is as follows –
<!DOCTYPE html>
<html lang="en" ng-app="ProjectTrackingModule">
<head>
<title>User Story Details</title>
<script src="../Scripts/jquery-2.1.0.min.js">
</script>
<link href="../CSS/amelia.bootstrap.min.css" rel="stylesheet" />
<link href="../CSS/Site.css" rel="stylesheet" />
<script src="../Scripts/angular.min.js">
</script>
<script src="../Scripts/bootstrap.min.js">
</script>
<script src="../Scripts/app.js">
</script>
<script src="../Controllers/UserStoriesController.js"></script>
</head>
<body ng-controller="UserStoriesController">
<h1>{{Title}}</h1>
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<td>
User Story ID
</td>
<td>
User Story
</td>
</tr>
</thead>
<tbody>
<tr class="success">
<td>
{{Stories.userStoryID}}
</td>
<td>
{{Stories.story}}
</td>
</tr>
</tbody>
</table>
</body>
</html>
The output of UserStoryDetails.html page is shown here:
Now add a controller for Project Tasks into our Controllers folder and write the following JavaScript code in the ProjectTasksController.js file –
(function () {
var ProjectTasksController = function ($scope, $http) {
var projectTasks = function (serviceResp) {
$scope.Tasks = serviceResp.data;
};
var errorDetails = function (serviceResp) {
$scope.Error = "Something went wrong ??";
};
$http.get("http://localhost:2464/api/ptprojecttasks/1")
.then(projectTasks, errorDetails);
$scope.Title = "Project Tasks Page";
};
app.controller("ProjectTasksController", ProjectTasksController);
}());
Add ProjectTaskDetails.html page into the Tasks folder. The ProjectTaskDetails.html page code is shown below –
<!DOCTYPE html>
<html lang="en" ng-app="ProjectTrackingModule">
<head>
<title>Project Task Details</title>
<script src="../Scripts/jquery-2.1.0.min.js">
</script>
<link href="../CSS/amelia.bootstrap.min.css" rel="stylesheet" />
<link href="../CSS/Site.css" rel="stylesheet" />
<script src="../Scripts/angular.min.js">
</script>
<script src="../Scripts/bootstrap.min.js">
</script>
<script src="../Scripts/app.js">
</script>
<script src="../Controllers/ProjectTasksController.js"></script>
</head>
<body ng-controller="ProjectTasksController">
<h1>{{Title}}</h1>
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<td>
Project Task ID
</td>
<td>
Start Date
</td>
<td>
End Date
</td>
<td>
Task Completion (%)
</td>
</tr>
</thead>
<tbody>
<tr class="success">
<td>
{{Tasks.projectTaskID}}
</td>
<td>
{{Tasks.taskStartDate}}
</td>
<td>
{{Tasks.taskEndDate}}
</td>
<td>
{{Tasks.taskCompletion}} %
</td>
</tr>
</tbody>
</table>
</body>
</html>
The output of ProjectTaskDetails.html page is shown here:
The last controller which we will add is ManagerCommentsController.js into our Controllers folder and write the following code in the file –
(function () {
var ManagerCommentsController = function ($scope, $http) {
var managerComments = function (serviceResp) {
$scope.Comments = serviceResp.data;
};
var errorDetails = function (serviceResp) {
$scope.Error = "Something went wrong ??";
};
$http.get("http://localhost:2464/api/ptmanagercomments/1")
.then(managerComments, errorDetails);
$scope.Title = "Manager comments Page";
};
app.controller("ManagerCommentsController", ManagerCommentsController);
}());
We will add ManagerCommentDetails.html page into ProjectManagement folder. The ManagerCommentDetails.html page code is shown below –
<!DOCTYPE html>
<html lang="en" ng-app="ProjectTrackingModule">
<head>
<title>Manager Comment Details</title>
<script src="../Scripts/jquery-2.1.0.min.js">
</script>
<link href="../CSS/amelia.bootstrap.min.css" rel="stylesheet" />
<link href="../CSS/Site.css" rel="stylesheet" />
<script src="../Scripts/angular.min.js">
</script>
<script src="../Scripts/bootstrap.min.js">
</script>
<script src="../Scripts/app.js">
</script>
<script src="../Controllers/ManagerCommentsController.js"></script>
</head>
<body ng-controller="ManagerCommentsController">
<h1>{{Title}}</h1>
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<td>
Comment ID
</td>
<td>
Comments
</td>
</tr>
</thead>
<tbody>
<tr class="success">
<td>
{{Comments.managerCommentID}}
</td>
<td>
{{Comments.comments}}
</td>
</tr>
</tbody>
</table>
</body>
</html>
The output of ManagerCommentsDetails.html page is shown here:
That’s it for this article. In Part IV of this series, we will look at Directives. While designing Views, we will make use of different directives which are available out-of-box in Angular JS.
Download the entire source code of this article (Github)
This article has been editorially reviewed by Suprotim Agarwal.
C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.
We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).
Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.
Click here to Explore the Table of Contents or Download Sample Chapters!
Was this article worth reading? Share it with fellow developers too. Thanks!
Pravinkumar, works as a freelance trainer and consultant on Microsoft Technologies. He is having over 10 years of experience in IT and is also a Microsoft Certified Trainer(MCT). He has conducted various corporate trainings on all versions of .NET Technologies including .NET, SharePoint Server, Microsoft SQL Server, Silverlight, ASP.NET, Microsoft PerformancePoint Server 2007 (Monitoring). He is passionate about learning new technologies from Microsoft. You can contact Pravinkumar at dabade[dot]pravinkumar [attherate] gmail[dot]com