A Mini SPA with ASP.NET MVC and AngularJS
SPA stands for Single Page Application; I think you already have little idea on it. Here I will demonstrate a mini SPA with ASP.NET MVC and AngularJS. So, let’s start.
Step 1: Create a ASP.NET MVC application with empty template
- Open visual studio, Got to File->New->Project
- Select Template -> Visual C# -> Web -> ASP.NET MVC 4 Web application and click OK
- Select Empty Template and Razor as view engine
Step 2: Install required packages
- Run the following command in Package Manager Console (Tools->Library Package Manager->Package Manager Console) to install required package.
- Make sure your internet connection is enabled.
PM> Install-Package jQuery
PM> Install-Package angularjs -Version 1.0.7
PM> Install-Package Newtonsoft.Json
Step 3: Create View model
In this application I will try to demonstrate two pages for Trainer and Training. For this purpose, create TrainerVM, TrainingVM, RegistrationVm view model in Model folder. JSONBuilder is a class in Model folder which make model as json serialized.
public class TrainingVm
{
public string TrainingCode { get; set; }
public string Title { get; set; }
public string Trainer { get; set; }
}
public class TrainerVm
{
public string Name { get; set; }
public string Email { get; set; }
public string Venue { get; set; }
}
public class RegistrationVm
{
public string Trainings { get; set; }
public string Trainers { get; set; }
}
public class JSONBuilder
{
public RegistrationVm BuildRegistrationVm()
{
var registrationVm = new RegistrationVm
{
Trainings = GetSerializedTraining(),
Trainers = GetSerializedTrainers()
};
return registrationVm;
}
public string GetSerializedTraining()
{
var trainings = new[]
{
new TrainingVm {TrainingCode = "TRA001", Title = "ASP.NET MVC 4", Trainer="Mahedee Hasan"},
new TrainingVm {TrainingCode = "TRA002", Title = "ASP.NET Web Form", Trainer="Asrafuzzaman"},
new TrainingVm {TrainingCode = "TRA003", Title = "AngularJs Fundamental", Trainer="Foysal Alam"},
new TrainingVm {TrainingCode = "TRA004", Title = "ASP.NET MVC 5 with web API", Trainer="Asfaquzzaman"},
};
var settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
var serializeCourses = JsonConvert.SerializeObject(trainings, Formatting.None, settings);
return serializeCourses;
}
public string GetSerializedTrainers()
{
var trainers = new[]
{
new TrainerVm {Name = "Mahedee Hasan", Email = "mahedee.hasan@gmail.com", Venue="Leadsoft Bangladesh Ltd"},
new TrainerVm {Name = "Asrafuzzaman", Email = "asraf@gmail.com", Venue="Leadsoft Bangladesh Ltd"},
new TrainerVm {Name = "Foysal Alam", Email = "foysal@gmail.com", Venue="Leadsoft Bangladesh Ltd"},
new TrainerVm {Name = "Asfaquzzaman", Email = "asfaq@gmail.com", Venue="Leadsoft Bangladesh Ltd"},
};
var settings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
var serializedInstructors = JsonConvert.SerializeObject(trainers, Formatting.None, settings);
return serializedInstructors;
}
}
Step 4: Create a RegistrationController in controller folder
public class RegistrationController : Controller
{
private JSONBuilder jsonBuilder = new JSONBuilder();
public ActionResult Index()
{
return View(jsonBuilder.BuildRegistrationVm());
}
}
Step 5: Create TrainingController and TrainerController
- Create TrainingsController.js and TrainersController.js in Scripts->Application->Controllers folder
TrainersController.js
'use strict';
registrationModule.controller("TrainersController", function ($scope, registrationData) {
$scope.trainers = registrationData.trainers;
});
TrainingsController.js
'use strict';
registrationModule.controller("TrainingsController", function ($scope, registrationData) {
$scope.trainings = registrationData.trainings;
});
I will define registrationModule and registrationData in next steps.
Step 6: Create registrationModule
- Create registrationModule.js in Scripts->Application. This is the configuration file for angular routing in client side.
var registrationModule = angular.module("registrationModule", [])
.config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/Registration/Trainings', {
templateUrl: '/templates/Trainings.html',
controller: 'TrainingsController'
});
$routeProvider.when('/Registration/Trainers', {
templateUrl: '/templates/trainers.html',
controller: 'TrainersController'
});
$locationProvider.html5Mode(true);
});
Here you might see that I map template and controller on corresponding routing. But I didn’t declare template yet. I will declare template in next steps.
Step 7: Create a layout page
- Create a layout page in Views-> Shared ->_Layout.cshtml and add reference of angularjs, jquery and registration module.
<html ng-app="registrationModule">
<head>
<script src="~/Scripts/angular.min.js"></script>
<script src="~/Scripts/jquery-2.1.1.js"></script>
<script src="~/Scripts/Application/registrationModule.js"></script>
<title>Training Registration</title>
@RenderSection("JavascriptInHead", required:false)
</head>
<body>
@RenderBody()
</body>
</html>
Step 8: Create Index view
- Right click on Index action of Registration controller and add a view. Modify the view as follows.
@model MiniSPA.Models.RegistrationVm
@{
ViewBag.Title = "Training Regirstration";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@section JavascriptInHead
{
<script src="~/Scripts/Application/Controllers/TrainersController.js"></script>
<script src="~/Scripts/Application/Controllers/TrainingsController.js"></script>
<script type="text/javascript">
registrationModule.factory('registrationData', function() {
return {
trainings: @Html.Raw(Model.Trainings),
trainers: @Html.Raw(Model.Trainers)
};
});
</script>
}
<div>
<div>
<div>
<div>
<ul>
<li><span>Training Registration</span></li>
</ul>
</div>
<div>
<ul>
<li><a href="/Registration/Trainings">Trainings Details</a></li>
<li><a href="/Registration/Trainers">Trainer Details</a></li>
</ul>
</div>
</div>
</div>
<div ng-view></div>
</div>
Step 9: Create template
- Create training.html and trainer.html in templates folder as follows
Trainer.html
<div class="row">
<div class="span10">
<h2>Instructors</h2>
</div>
</div>
<div class="row">
<div class="span10">
<table class="table table-condensed table-hover">
<tr>
<th>Trainer Name</th>
<th>Email</th>
<th>Venue</th>
</tr>
<tr ng-repeat="trainer in trainers">
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
Training.html
<div>
<div>
<h2>Training Details</h2>
</div>
</div>
<div>
<div>
<table>
<tr>
<th>Training Code</th>
<th>Training Title</th>
<th>Trainer Name</th>
</tr>
<tr ng-repeat="training in trainings">
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
Step 10: Modify RouteConfig.cs
- Modify the RouteConfig.cs as follows for routing Registration controller default and catching all other parameter.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Mini SPA",
url: "Registration/{*catchall}",
defaults: new { controller = "Registration", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Registration", action = "Index", id = UrlParameter.Optional }
);
}
}
This structure is not best. So it is not recommended for large application. For large application use service. Hope, I will publish a complete SPA soon. Thanks for your patient!