AngularJS feat. Web API

Developing Web applications using AngularJS and Web API can be quite amuzing. You can pick this architecture in case you have in mind a web application with limitted page refreshes or post backs to the server while each application’s View is based on partial data retrieved from it. If this is what you want, then Web API would be responsible to serve the data and AngularJS to display them in an elegant way. The most important decisions you need to make when you start developing using these two frameworks, are the following:

What project template to use?

How and where to structure AngularJS?

What happens in page refreshes?

What type of authentication to use and how AngularJS can help with that?

We are going to answer all these questions by building a Gadget Store web application using AngularJS for front end and ASP.NET Web API as the back end. This will be done through two posts where this one will present you how to create all the required infrastructure (database, web api and angularjs level) while the second one will show you how to setup the authentication logic in your application. Let’s start.
Create a black solution named GadgetStore in Visual Studio and add the following projects:

Domain (Class library)

DataAccess (Class library)

Store (Empty Web Application with templates MVC and Web API checked)

Let’s build our domain models first. We will use Entity Framework Code First development. Suppose that we are a company that sells Gadgets such as tablets, mobiles etc. Our provider has a website (our application) where we can order the gadgets we want to supply our customers. Hence, we need some classes to describe gadgets, gadget categories and orders. Add the following classes to the domain project.

Now let’s switch to the DataAccess project and configure Entity Framework. Make sure you add a reference to the Domain project and install Entity Framework from Nuget Packages. Add a Configurations folder and add the following two classes to it.

We want to manual set Category.CategoryID for gadget categories and also to ignore Order.Gadgets for our model. The latter will result that the database table Order will hold properties for all specified except for the Gadgets. To create our entities add the following class to the root of the current project.

You can see that I have used specific images for the gadgets. Those images will be stored in an images folder in the MVC project so you can either use your own or simply download the solution we are building and follow along. Now it’s time to switch to the ASP.NET MVC project. First thing you need to do, is add references to both of the class library projects and install Entity Framework as well. In the Global.asax class we need to set the database initializer as follow:

We are not gonna use all of the controllers actions that’s why I highlighted those that the AngularJS application will invoke for sure. At this very point you can build the application and request the gadgets from the browser. Ensure that the database has been successfully created.

Before starting your application you may have to set System.Web.Mvc reference, Copy Local property to True, from the properties window.

AngularJS

It’s time to setup our AngularJS components. Mind that this is not an AngularJS tutorial so I assume you have already some experience developing with AngularJS. If you don’t however, that’s fine, this is a good opportunity to understand how this framework makes easy to develop SPA Web Applications using the Web API. So, to start with, install Bootstrap and AngularJS from Nuget Packages. This will add a Scripts, fonts and Content folder to your application with the required components for the installed frameworks. When I told you to create the Web application project I mentioned to leave both the MVC and Web API templates options checked. Well, the idea is to have some pure MVC controllers that responds to certain routes and aspects of your application. When an MVC view is render, multiple related views can be render dynamically using AngularJS features without posting back to server.
We need to set an initial view for our store application so let’s do it. Add an MVC Controller in the controllers directory named HomeController if not already exists.

Right click inside the Index action and add a View. Set the View’s name as Index and make sure you leave all the checkboxes unchecked. This will create our basic View under the Views/Home/Index.cshtml View file. You can see a ViewOrder action but for now we can skip it’s purpose. Before show you Index’s code let’s create AngularJS required folders for our app. Create an app folder at the root directory and add a main.App.js javascript file. This will be AngularJS bootstrap file (do not confuse it with CSS related bootstrap). Under the same folder add the following ones:

OK, take a deep breath now.. I know we haven’t created most of the referenced scripts till now but we will do so step by step while explaining the purpose of each file or component. You can run your application when we finish adding all the required files to our application. For demonstration purposes, every time we add a view I will show you how the result will look like when you complete this post. Take a look at the highlighted lines 5,10,26,29 It’s time to tell AngularJS that we want to handle this HTML page as an AngularJS application. The top level module of our application is named gadgetsStore and it’s being setup at the mainApp.js top level javascript file. gadgetStoreCtrl controller is the top lever controller, responsible to retrieve or post data to the server. As a top lever controller makes inner views controllers able to share data. The ng-view tells angular that this is where we want our partial views to be render when asked. Let’s see now the mainApp.js code.

Here we created the basic application’s module while injecting some of our custom modulesstoreFilters, storeCart plus AngularJS ngRoute for setting our routing system.
Add a gadgetStoreCtrl.js file in the app/controllers folder.

This controller is responsible for fetching gadgets from the GadgetsController and categories from the CategoriesController. Moreover, using the sendOrder function can post Orders back to server.
Since this controller is applied at the Index.cshtml body element, the $scope.data is accessible through all the views rendered in this file. Now let’s take one by one the routes and add the required files. The first of our routes (/gadgets) will render a gadgets.html partial view so add this file under app/views/ folder.

This View is responsible to display a left bootstrap column with all the Gadget categories and the basic column where all the Gadgets with their details are displayed. It’s controller gadgetsCtrl is responsible to display specific category’s gadgets when some of them is clicked, paging through the gadgets and adding gadgets to a cart. Add a gadgetsCtrl.js file under the app/controllers folder.

Take a look at the first line of code. When we call AngularJS module function without the injected modules array, we actually asks for angular to return and not to create the specific module. The second route we setup at the beginning was the /checkout which renders the partial view checkout.html. Add this file under app/views.

You will propably have noticed that some of our controllers are injected a cart factory component. Let’s create this as well. You can understand that a cart can be considered as an abstract component by itself and that’s why we are going to add the relative files to the app/components folder.

Beside the factory methods thar are able to add or remove gadgets from the cart, I would like to point out the custom directive for rendering our cart details. You can see that we named our directive cartDetails but in the Index.cshtml file we add a cart-details custom html element.. This is a convention that AngularJS expects from custom directives.

This is a common bootstrap form with some validation applied on it. The complete order button is activated only if all fields are filled. Now if you remember we told our top level controller (gadgetsStore) that when the order is submitted successfully or not, change the location to /complete. This is done via the $location AngularJS service.

Notice also that on success, we read the location header result from the OrdersController POST action in order to render a link to our submitted order. Add the orderSubmitted.html partial view under the app.views folder.

For each order I display the basic details but for each distint gadget in that order, I decided to render a partial view. This way we can keep things cleaner. Add a new folder named Shared if not exist under the Views folder and create a partial view named Order. This partial view accepts a Gadget object and renders it’s details.

Believe it or not, we are done. Now you can build and run your application and hopefully you will not receive any errors. If you do so, you can always download the complete solution at the bottom of this post.

Food for thought

When you decide to build applications using AngularJS, be prepared for having a lots of files (mostly javascript and html) to manipulate. The structure we used it’s good ONLY for small size applications and only. If you had a larger application you would need a different folder structure to host your AngularJS components. We can talk more about this in an upcoming post. We saw how to use Web API to fetch or post data from and to the server respectively, but we haven’t setup any authentication logic to our application yet. More over, if you refresh the page, you will see that you lose instantly any gadgets you have added to your cart. Well.. this is what we ‘re gonna see in the next post, so make sure you follow the blog to get notified!
Download the project we built from here. I hope you enjoyed the post!

This is a great article. Keep up the good work.
Just a question, Why did you have a default constructor for Order in which you make a new list of Gadgets but for Category you don’t do this though you have a list of gadgets(public List Gadgets { get; set; }). Please explain this.

The purpose of this blog is to broaden my education, promote experimentation and enhance my professional development. Albert Einstein once said that “If you can’t explain it simply, you don’t understand it well enough” and I strongly believe him!