The Fairway Technologies Blog

blog

Apply Angular Techniques to jQuery Applications - Part 2

In WebAPI, Angular, CodeProject No Comments

In the last blog post you learned how to structure your jQuery applications like Angular applications. You created a single page on which to host all your other pages. In this post you are going to put those techniques to work by building a complete list, add, edit and delete page as shown in Figure 1 and Figure 2. You are going to use a Person table full of data such as First Name, Last Name, Email and Salary data for a set of people.

AngularTechniques-Fig1.png

Figure 1: Person List Page

AngularTechniques-Fig2.png

Figure 2: Person Detail Page

Create Server-Side Code

There are several pieces you need to create on the server-side to prepare for calling a Web API from your client-side jQuery CRUD page. You need to do the following.

  1. Create a person table
  2. Create a web project in Visual Studio 2017
  3. Create Entity Framework classes to access your person table
  4. Create base Web API controller class
  5. Create Person Web API controller
  6. Change JSON formatter to return camel-case property name

Person Table

To have some data for this page, create a table in a SQL Server database. Below is the script to create the Person table.

CREATE TABLE Person (
PersonId int PRIMARY KEY NONCLUSTERED
IDENTITY(1,1) NOT NULL,
FirstName varchar(50) NOT NULL,
LastName varchar(50) NOT NULL,
EmailAddress varchar(250) NULL,
StartDate datetime NULL,
Salary money NULL
);

Once you have this table created, add some data. You may download the samples for this blog post and use the Person.sql script provided to create this table and the data. See the Summary section at the end of this blog post for information on how to download the sample.

Web Project

For this blog post, I am going build the sample project using Visual Studio 2017. Start Visual Studio 2017 and select File | New | Project… from the menu system. From the New Project dialog, select Visual C# | Web | ASP.NET Web Application (.NET Framework). Set the Name to jQueryCRUD and click the OK button. On the New ASP.NET Web Application dialog, select the Web API template and click the OK button to create your web project.
After the project has been created, right mouse-click on the project and select Manage NuGet Packages… from the context-sensitive menu. Click on the Updates tab and if there are any updates, select all packages and update all of them.

Entity Framework Classes

You need a data layer to be able to retrieve and modify the data in the Person table. Use the Entity Framework code generator that is built-into Visual Studio to create this data layer. This code generator generates code to allow us to retrieve, add, edit and delete data within the Person table.

Right mouse-click on the \Models folder and select Add | New Item… Click on the Data node, then select ADO.NET Entity Data Model from the list of templates. When prompted for the item name, type in PersonDB. Click the Add button to move to the next step in this process.

Select Code First from database and click the Next button to create a server connection. Create a new connection to the database where you installed the Person table. After creating the connection, leave everything else the same in this step of the wizard and click the Next button.

Expand the tree view and locate the Person table you previously created. Click the Finish button to have Visual Studio create the Entity Framework data model for the Person table.

Base Web API Controller Class

All Web API controllers you create in Visual Studio inherit from the ApiController class. It is a good practice to create your own base class that inherits from ApiController, then have all your Web API controllers inherit from your base class. By doing this, you can add methods and properties to your base controller class that you can use among all your Web API controllers.

Add a new folder named \Components to your project. Right mouse-click on the Components folder and add a new class called BaseApiController. Into this new class you are going to add two new methods. The first method is going to help each controller deal with exceptions. The second method is going to convert any validation exceptions returned from the Entity Framework into a ModelStateDictionary to be returned to the client application. Add some using statements to the top of this new class.

using System;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.Web.Http;
using System.Web.Http.ModelBinding;

Write the rest of the BaseApiController class by typing in the following code:


public class BaseApiController : ApiController
{
protected IHttpActionResult HandleException(Exception ex,
string msg) {
IHttpActionResult ret;

// TODO: Add exception publishing here
Debug.WriteLine(ex.ToString());

// Create new exception with generic message
ret = InternalServerError(new Exception(msg, ex));

return ret;
}

protected ModelStateDictionary
ConvertToModelState(DbEntityValidationException ex)
{
ModelStateDictionary ret = new ModelStateDictionary();

foreach (var list in ex.EntityValidationErrors) {
foreach (var item in list.ValidationErrors) {
ret.AddModelError(item.PropertyName,
item.ErrorMessage);
}
}

return ret;
}
}

The HandleException method is used in the catch block of any method in your controllers. If an exception, other than a validation exception, is raised by code in your method, you pass the exception object to this method. It creates a status code of 500 by returning an IHttpActionResult created from the InternalServerError() method.

The method ConvertToModelState is used when you attempt to add, or update a person and a business rule fails. The Entity Framework raises a DbEntityValidationException exception when business rules fail. You are going to pass that exception object to this method. The validation errors in this exception are extracted and bundled into a ModelStateDictionary object. This dictionary object is passed back to the client by returning the BadRequest method with the dictionary object as the payload.

Person Controller Class

Open the Controllers folder and delete the ValuesController.cs file. This is just a sample and is not needed. Right mouse-click on the Controllers folder and select Add | Web API Controller Class (v2.1) from the menu. Set the name to PersonController and click the OK button. Add a few using statements at the top of this file.

using System;
using System.Data.Entity.Validation;
using System.Linq;
using System.Web.Http;
using jQueryCRUD.Components;
using jQueryCRUD.Models;

Delete all the code within this new controller class as you are going to write your Web API methods using a more updated approach than what is generated by Visual Studio. There are five methods you are going to add to this controller; Get(), Get(id), Post(), Put() and Delete(). Modify the PersonController class to inherit from BaseApiController instead of ApiController.
The code in each of these methods has some commonalities. Each defines an instance of a PersonDB object and creates a new instance of that object within a try…catch block. The catch block calls the HandleException() method you previously defined within the BaseApiController.

The Get() and Get(id) methods return an Ok() or a NotFound() status depending on whether or not they found any data. The Put() and Post() methods can return a BadRequest() if a null person object is passed in, or if validation exceptions are generated from the Entity Framework. The complete PersonController class is presented below.

[RoutePrefix("api/Person")]
public class PersonController : BaseApiController
{
[HttpGet()]
public IHttpActionResult Get()
{
PersonDB db = null;
IHttpActionResult ret = null;

try {
db = new PersonDB();

if (db.People.Count() > 0) {
ret = Ok(db.People);
}
else {
ret = NotFound();
}
}
catch (Exception ex) {
ret = HandleException(ex,
"Error attempting to retrieve a list of persons");
}

return ret;
}

[HttpGet()]
public IHttpActionResult Get(int id)
{
PersonDB db = null;
IHttpActionResult ret = null;
Person person = null;

try {
db = new PersonDB();

person = db.People.Find(id);
if (person != null) {
ret = Ok(person);
}
else {
ret = NotFound();
}
}
catch (Exception ex) {
ret = HandleException(ex,
"Error attempting to retrieve a single person");
}

return ret;
}

[HttpPost()]
public IHttpActionResult Post([FromBody]Person person)
{
PersonDB db = null;
IHttpActionResult ret = null;

try {
db = new PersonDB();

if (person != null) {
db.People.Add(person);
db.SaveChanges();
ret = Created<Person>(Request.RequestUri +
person.PersonId.ToString(),
person);
}
else {
ret = BadRequest(
"Invalid person object passed to POST method");
}
}
catch (DbEntityValidationException ex) {
ret = BadRequest(ConvertToModelState(ex));
}
catch (Exception ex) {
ret = HandleException(ex,
"Error attempting to insert person data");
}

return ret;
}

[HttpPut()]
public IHttpActionResult Put([FromBody]Person person)
{
PersonDB db = null;
IHttpActionResult ret = null;

try {
db = new PersonDB();

if (person != null) {
db.Entry(person).State =
System.Data.Entity.EntityState.Modified;
db.SaveChanges();
ret = Ok(person);
}
else {
ret = BadRequest(
"Invalid person object passed to PUT method");
}
}
catch (DbEntityValidationException ex) {
ret = BadRequest(ConvertToModelState(ex));
}
catch (Exception ex) {
ret = HandleException(ex,
"Error attempting to update person data");
}

return ret;
}

[HttpDelete()]
public IHttpActionResult Delete(int id)
{
PersonDB db = null;
IHttpActionResult ret = null;
Person person = null;

try {
db = new PersonDB();

person = db.People.Find(id);
if (person != null) {
db.People.Remove(person);
db.SaveChanges();
}
ret = Ok(true);
}
catch (Exception ex) {
ret = HandleException(ex,
"Error attempting to delete person data");
}

return ret;
}
}

Camel-Case Property Names

C# property names are generated from the Entity Framework using PascalCase. However, JavaScript programmers are used to camelCase property names. You can have .NET automatically convert the C# property names to camelCase by adding a little bit of code in the Register() method in the WebApiConfig class. Open the \App_Start\WebApiConfig.cs file and make sure you have the following using statements at the top of this file.

using System.Linq;
using System.Net.Http.Formatting;
using System.Web.Http;
using Newtonsoft.Json.Serialization;

At the bottom of the Register() method, add the following code to perform the camel-case conversion.

// Make return results camel case
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>()
.FirstOrDefault();

jsonFormatter.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();

The above code queries the Formatters collection and retrieves the first instance of a JsonMediaTypeFormatter object it finds. Into the SerializerSettings.ContractResolver property create a new instance of a CamelCasePropertyNamesContractResolver. This property controls how the JSON objects are formatted and sent to the client-side caller.

Display a List of Person Data

If you have not already done so, please read the first part of this blog post. Or, at least download the sample from that blog post as you need the code from that post to continue. You can get the samples at www.pdsa.com/downloads. Choose “PDSA Blogs” from the Category, then select “Apply Angular Techniques to jQuery Applications - Part 1”.
With the server-side code in place, you are now ready to create the HTML and the JavaScript/jQuery for the client-side code. To do this, you are going to perform a few tasks.

  1. Copy files from previous blog post
  2. Create a person.service.js file to call the Web API
  3. Add mustache.js (or any templating framework) to your project
  4. Create a person.list.html file to list all persons
  5. Create a person.list.js file to call the person service and load the list of persons into an HTML table
  6. Create a person.detail.html file to allow for inputting person information
  7. Create a person.detail.js file to retrieve, add, and edit person data

Copy Files from Previous Post

Locate the \src folder in the samples from the previous blog post and copy the complete folder into your Visual Studio project. Copy the spa-common.js file from the \scripts folder and paste it into the \Scripts folder of your project. Right mouse-click on the \src\index.html file and choose Set As Start Page from the context-sensitive menu. Run the project and make sure your index.html page loads correctly.

Add Mustache.js to your Project

Instead of writing a bunch of code in JavaScript to load the person table, let’s use a templating framework to build the table. There are many different templating frameworks you can utilize. I am going to use Mustache.js (https://github.com/janl/mustache.js/) for this article. Feel free to substitute your favorite templating framework. Open the NuGet Package Manager in your Visual Studio project and search for Mustache.js as shown in Figure 3. Install mustache into your project.

AngularTechniques-Fig3.png

Figure 3: Add mustache.js to your project

Add a link on the index.html page to the \Scripts\mustache.js file.

<script src="../Scripts/mustache.js"></script>

Create Person Service Closure

Let’s start building our person files. Right mouse-click on the \src folder and add a new folder called \person. Add a new JavaScript file named person.service.js. Add a closure and assign it to a variable called PersonService. In this closure you are going to add all the methods required to retrieve all persons, get a single person, insert, update and delete a person, by calling the Person Web API you created earlier in this post.

Start by creating a method named getAll(). This method makes an ajax call to the Get() method in your Web API controller. To this method you pass two callback functions. The first function is called when person data is successfully retrieved from the ajax call. The second function is called when an exception occurs.

var PersonService = (function () {
const API_URL = "/api/Person/";

function getAll(success, failure) {
// Get a list of data
$.ajax({
url: API_URL,
type: 'GET',
dataType: 'json'
})
.done(function (data) {
success(data);
})
.fail(function (error) {
if (failure) {
failure(error);
}
else {
console.log("Error Occurred: " + error);
}
});
}

// Public Functions
return {
getAll: function (success, failure) {
getAll(success, failure);
}
};
})();

Add a link on the index.html page to the person.service.js file.

<script src="person/person.service.js"></script>

Create Person List HTML

Create a person.list.html file in the \person folder and add the appropriate HTML to build a person table. Leave the <tbody> element blank. This will be filled in by using the template defined in the <script> tag with the id of “dataTmpl”.

<div class="row">
<div class="col-xs-12">
<h1>Person List</h1>
</div>
</div>

<div class="row">
<div class="col-xs-12">
<table id="people" class="table table-bordered table-condensed table-striped">
<thead>
<tr>
<th>Person ID</th>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
<th class="text-right">Salary</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>

<script src="./person/person.list.js"></script>
<script id="dataTmpl" type="text/html">
{
Plan Your Technology Team with This Online Assessment Tool

Subscribe to Email Updates

Build a Rock Start Tech Team with This Online Assessment | Fairway Tech