Introducing AngularJs
Before we dig further let's talk about a quick overview of AngularJs and Web API in MVC 6.
AngularJs is a client-side MVC framework written in JavaScript. It runs in a web browser and greatly helps us (developers) to write modern, single-page, AJAX-style web applications. It is a general purpose framework, but it shines when used to write CRUD (Create Read Update Delete) type web applications.
Introducing Web API
ASP.NET Web API is a framework that makes it easy to build HTTP services that reach a broad range of clients, including browsers and mobile devices. ASP.NET Web API is an ideal platform for building RESTful applications on the .NET Framework. In ASP.NET 5, Web API is now part of MVC 6.
If you are new to ASP.NET 5 then I would suggest you to read the following articles below to learn more about the new features in ASP.NET:
Creating an ASP.NET 5 Project
To start fire up Visual Studio 2015 and create a new ASP.NET 5 project by selecting File > New Project. In the dialog, under Templates > Visual C#, select ASP.NET Web Application as shown in the figure below:
Figure 1: New Project dialog
Name your project to whatever you like and then click OK. For the example I named the project as “AngularJS101”. Now after that you should be able to see the “New ASP.NET Project” dialog:
Figure 2: New ASP.NET Project dialog
Now select ASP.NET 5 Preview Empty template from the dialog above. Then click OK to let Visual Studio generate the necessary files and templates needed for you. You should be able to see something as in the following:
Figure 3: New default ASP.NET 5 Empty project structure
Adding the Scripts folder
The next thing to do is to create a new folder called “Scripts”. This folder will contain all the JavaScript files needed in our application:
Figure 4: The Scripts folder
Getting the Required Packages
ASP.NET 5 now supports three main package managers: NuGet, NPM and Bower.
Package Manager
A package manager enables you to easily gather all resources that you need for building an application. In other words, you can use the package manager to automatically download all the resources and their dependencies instead of manually downloading project dependencies such as jQuery, Bootstrap and AngularJs from the web.
NuGet: NuGet manages .NET packages such as Entity Framework, ASP.NET MVC and so on. You typically specify the NuGet packages that your application requires within a project.json file.
NPM: NPM is one of the newly supported package managers in ASP.NET 5. This package manager was originally created for managing packages for the open-source NodeJS framework. The package.json is the file that manages your project's NPM packages.
Bower: Bower is another supported package manager in ASP.NET 5. It was created by Twitter that is designed to support front-end development. You can use Bower to manage client-side resources such as jQuery, AngularJs and Bootstrap.
For this example we need to use NPM to install the resources we need in our application such as Grunt and the Grunt plugins. To do this just right-click in the Project (in this case AngularJS101) and select Add > New Item. In the dialog select NPM configuration file as shown in the figure below:
Figure 5: Adding NPM config file
Click Add to generate the file for you. Now open package.json file and modify it by adding the following dependencies:
- {
- "version": "1.0.0",
- "name": "AngularJS101",
- "private": true,
- "devDependencies": {
- "grunt": "0.4.5",
- "grunt-contrib-uglify": "0.9.1",
- "grunt-contrib-watch": "0.6.1"
- }
- }
Notice that you get Intellisense support while you edit the file. A matching list of NPM package names and versions shows as you type.
In
package.json file, from the code above, we have added three (3) dependencies named
grunt, grunt-contrib-uglify and
grunt-contrib-watch NPM packages that are required in our application.
Now save the package.json file and you should be able to see a new folder under Dependencies named NPM as shown in the following:
Figure 6: NPM dependencies
Right-click on the NPM folder and select
Restore Packages to download all the packages required. Note that this may take a bit to finish the download so just be patient and wait ;). Then the grunt, grunt-contrib-uglify and grunt-contrib-watch NPM packages should now be installed as shown in the following:
Figure 7: Installing NPM dependencies
Configuring Grunt
Grunt is an open-source tool that enables you to build client-side resources for your project. For example, you can use Grunt to compile your LESS or Saas files into CSS. Adding to that, Grunt can also be used to minify CSS and JavaScript files.
In this example, we will use Grunt to combine and minify JavaScript files. We will configure Grunt so that it will take all the JavaScript files from the Scripts folder that we created earlier, combine and minify the files and finally save the results to a file named
app.js within the
wwwroot folder.
Now right-click on your project and select Add > New Item. Select Grunt Configuration file from the dialog as shown in the figure below:
Figure 8: Adding Grunt config file
Then click
Add to generate the file and then modify the code within the
Gruntfile.js file so it will look like this:
- module.exports = function (grunt) {
- grunt.loadNpmTasks('grunt-contrib-uglify');
- grunt.loadNpmTasks('grunt-contrib-watch');
-
- grunt.initConfig({
- uglify: {
- my_target: {
- files: { 'wwwroot/app.js': ['Scripts/app.js', 'Scripts/**/*.js'] }
- }
- },
- watch: {
- scripts: {
- files: ['Scripts/**/*.js'],
- tasks: ['uglify']
- }
- }
- });
- grunt.registerTask('default', ['uglify', 'watch']);
- };
The code above contains three sections. The first one is used to load each of the Grunt plugins that we need from the NPM packages that we configured earlier. The
initConfig() is responsible for configuring the plugins. The
Uglify plugin is configured so that it combines and minifies all the files from the Scripts folder and generate the result in a file named app.js within
wwwroot folder. The last section contains the definitions for your tasks. In this case we define a single "default" task that runs "uglify" and then watches for changes in our JavaScript file.
Now save the file and let's run the Grunt file using Visual Studio Task Runner Explorer. To do this, go to View > Other Windows > Task Runner Explorer in Visual Studio main menu. In the Task Runner Explorer be sure to hit the refresh button to load the tasks for our application. You should see something like this:
Figure 9: The Visual Studio Task Runner Explorer
Now right-click on the
default task and select
Run. You should be able to see the following output:
Figure 10: Running Task Runner
Configuring ASP.NET MVC
There are two main files that we need to modify to enable MVC in our
ASP.NET 5 application.
First, we need to modify the
project.json file to in include MVC 6 under dependencies:
- "webroot": "wwwroot",
- "version": "1.0.0-*",
- "dependencies": {
- "Microsoft.AspNet.Server.IIS": "1.0.0-beta3",
- "Microsoft.AspNet.Mvc": "6.0.0-beta3"
- },
- "frameworks": {
- "aspnet50": { },
- "aspnetcore50": { }
- },
Be sure to save the file to restore the packages required. The project.json file is used by the NuGet package manager to determine the packages required in your application. In this case we've added
Microsoft.AspNet.Mvc.
Now the last thing is to modify the
Startup.cs file to add the MVC framework in the application pipeline. Your Startup.cs file should now look like this:
- using System;
- using Microsoft.AspNet.Builder;
- using Microsoft.AspNet.Http;
- using Microsoft.Framework.DependencyInjection;
- namespace AngularJS101
- {
- public class Startup
- {
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddMvc();
- }
- public void Configure(IApplicationBuilder app)
- {
- app.UseMvc();
- }
- }
- }
The
ConfigureServices() method is used to register MVC with the ASP.NET 5 built-in Dependency Injection Framework (DI). The
Configure() method is used to register MVC with OWIN.
Adding Models
The next step is to create model that we can use to pass data from the server to the browser /client. Now create a folder named “Models” under the root of your project. Within the “
Models” folder, create a class named “
DOTAHero” and add the following code below:
- using System;
-
- namespace AngularJS101.Models
- {
- public class DOTAHero
- {
- public int ID { get; set; }
- public string Name { get; set; }
- public string Type { get; set; }
- }
- }
Create another class called “
HeroManager” and add the following code below:
- using System.Collections.Generic;
- using System.Linq;
- namespace AngularJS101.Models
- {
- public class HeroManager
- {
- readonly List<DOTAHero> _heroes = new List<DOTAHero>() {
- new DOTAHero { ID = 1, Name = "Bristleback", Type="Strength"},
- new DOTAHero { ID = 2, Name ="Abbadon", Type="Strength"},
- new DOTAHero { ID = 3, Name ="Spectre", Type="Agility"},
- new DOTAHero { ID = 4, Name ="Juggernaut", Type="Agility"},
- new DOTAHero { ID = 5, Name ="Lion", Type="Intelligence"},
- new DOTAHero { ID = 6, Name ="Zues", Type="Intelligence"},
- new DOTAHero { ID = 7, Name ="Trent", Type="Strength"},
- };
- public IEnumerable<DOTAHero> GetAll { get { return _heroes; } }
-
- public List<DOTAHero> GetHeroesByType(string type) {
- return _heroes.Where(o => o.Type.ToLower().Equals(type.ToLower())).ToList();
- }
- public DOTAHero GetHeroByID(int Id) {
- return _heroes.Find(o => o.ID == Id);
- }
- }
- }
The
HeroManager class contains a readonly property that contains a list of heroes. For simplicity, the data is obviously static. In real scenario you may need to get the data in a storage medium such as database or any files that stores your data. It also contain a
GetAll property that returns all the heroes and a
GetHeroesByType() method that returns a list of heroes based on the hero type and finally a
GetHeroByID() method that returns a hero based on ID.
Adding Web API Controller
For this specific example, we will be using Web API for passing data to the browser/client.
Unlike previous versions of ASP.NET, MVC and Web API controllers used the same controller base class. Since Web API is now part of MVC 6 then we can start creating Web API controllers because we already pulled the required NUGet packages for MVC 6 and configured MVC 6 in startup.cs.
Now add an “
API” folder under the root of the project:
Figure 11: The API folder
Then add a Web API controller by right-clicking the API folder and selecting Add > New Item. Select
Web API Controller Class and name the controller as “
HeroesController” as shown in the figure below:
Figure 12: Adding Web API controller
Click Add to generate the file for you. Now modify your
HeroesController class by adding the following code below:
- using System.Collections.Generic;
- using Microsoft.AspNet.Mvc;
- using AngularJS101.Models;
-
- namespace AngularJS101.API.Controllers
- {
- [Route("api/[controller]")]
- public class HeroesController : Controller
- {
-
- [HttpGet]
- public IEnumerable<DOTAHero> Get()
- {
- HeroManager HM = new HeroManager();
- return HM.GetAll;
- }
-
-
- [HttpGet("{id}")]
- public DOTAHero Get(int id)
- {
- HeroManager HM = new HeroManager();
- return HM.GetHeroByID(id);
- }
-
- }
- }
At this point we will only be focusing on GET methods to retrieve data. The first GET method returns all the heroes available by calling the GetAll property found in HeroManager class. The second GET method returns a specific hero data based on the ID.
You can test whether the actions are working by running your application in the browser and appending the
/api/heroes in the URL. Here are the outputs for both GET actions.
Route: /api/heroesFigure 13: GetAll result
Route: /api/heroes/7
Figure 14: GetHeroByID result
Creating the AngularJs Application
Visual Studio 2015 includes templates for creating AngularJs modules, controllers, directives and factories. For this example we will be displaying the list of heroes using an AngularJs template.
Adding an AngularJs Module
To get started let's create an AngularJs module by right-clicking on the Scripts folder and selecting Add > New Item. Select
AngularJs Module as shown in the figure below.
Figure 15: Adding AngularJs Module
Click Add to generate the file and copy the following code for our AngularJs module:
- (function () {
- 'use strict';
-
- angular.module('heroesApp', [
- 'heroesService'
- ]);
- })();
The code above defines a new AngularJs module named “heroesApp”. The heroesApp has a dependency on another AngularJs module named “heroesService” that we will create later in the next step.
Adding an AngularJs Controller
The next thing to do is to create a client-side AngularJs Controller. Create a new folder called “
Controllers” under the Script folder as in the following:
Figure 16: AngularJs Controllers folder
Then right-click on the
Controllers folder and select Add > New Item. Select
AngularJs Controller using $scope as shown in the figure below:
Figure 17: Adding AngularJs Controller file
Click Add and copy the following code below within your heroesController.js file:
- (function () {
- 'use strict';
-
- angular
- .module('heroesApp')
- .controller('heroesController', heroesController);
-
- heroesController.$inject = ['$scope','Heroes'];
-
- function heroesController($scope, Heroes) {
- $scope.Heroes = Heroes.query();
- }
- })();
The code above depends on the Heroes service that supplies the list of heroes. The Heroes service is passed to the controller using dependency injection (DI). The $inject() method call enables DI to work. The Heroes service is passed as the second parameter to the heroesController() function.
Adding the Heroes Service
We will use an AngularJs Heroes service to interact with our data via Web API. Now add a new folder called “Services” within the Script folder. Right-click on the Services folder and select Add > New Item. From the dialog select
AngularJs Factory and name it “
heroesService.js” as in the following:
Figure 18: Adding AngularJs Factory file
Now click Add and then replace the generated default code with the following:
- (function () {
- 'use strict';
- var heroesService = angular.module('heroesService', ['ngResource']);
- heroesService.factory('Heroes', ['$resource',
- function ($resource) {
- return $resource('/api/heroes', {}, {
- query: { method: 'GET', params: {}, isArray: true}
- });
- }
- ]);
- })();
The code above basically returns a list of heroes from the Web API action. The $
resource object does an AJAX request using a RESTful pattern. The
heroesService is associated with the /api/heroes route on the server. This means that when you do a query against the service from your client-side code, the Web API HeroesController is invoked to return a list of heroes.
Adding an AngularJs Template
Let's add an AngularJs template for displaying the list of heroes. To do this we will need an HTML page to render in the browser. In the
wwwroot folder add a new HTML page and name it “index” for simplicity. Your application structure should now look like this:
Figure 19: Adding the Index.html page
The
wwwroot folder is a special folder in your application. The purpose is that the wwwroor folder
should contain all the contents of your website such as HTML files and images needed for your website.
You
should not place any of your source code within the wwwroot folder. Instead source codes such as MVC controller's source, model classes and unminified JavaScript and LESS files should be place
outside of the wwwroot folder.
Now replace the contents of the index.html with the following:
- <!DOCTYPE html>
- <html ng-app="heroesApp">
- <head>
- <meta charset="utf-8" />
- <title>DOTA 2 Heroes</title>
- <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.js"></script>
- <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular-resource.js"></script>
- <script src="app.js"></script>
- </head>
- <body ng-cloak>
- <div ng-controller="heroesController">
- <h1>DOTA Heroes</h1>
- <table>
- <thead>
- <tr>
- <th>ID</th>
- <th>Name</th>
- <th>Type</th>
- </tr>
- </thead>
- <tbody>
- <tr ng-repeat="hero in Heroes">
- <td>{{hero.ID}}</td>
- <td>{{hero.Name}}</td>
- <td>{{hero.Type}}</td>
- </tr>
- </tbody>
- </table>
- </div>
- </body>
- </html>
There are several things to point out from the markup above.
The <html> element is embedded with the
ng-app directive. This directive associates the heroesApp with the HTML file.
In the <script> section, you will see that I use Google CDN for referencing AngularJs and related libraries. Besides being lazy, it's my intent to use CDN for referencing standard libraries such as jQuery, AngularJs and Bootstrap to boost application performance. If you don't want to use CDN then you can always install AngularJs packages using Bower.
The <body> element is embedded with the ng-cloak directive. This directive hides an AngularJs template until the data has been loaded in the page.
The <div> element within the <body> block is embedded with the ng-controller directive. This directive associates the heroesController and renders the data within the <div> element.
Finally, the
ng-repeat directive is added to the <tr> element of the <table>. This will create a row for each data retrieved from the server.
Output
The following is the output of running the page and navigating to index.html:
Figure 20: Application output
That's it! I hope you will find this article useful and fun. Stay tuned for more!