Learning AngularJS by Example – The Customer Manager Application

Updated: 9/23/2014

I’m always tinkering around with different ideas and toward the beginning of 2013 decided to build a sample application using AngularJS that I call Customer Manager. The goal of the application is to highlight a lot of the different features offered by AngularJS and demonstrate how they can be used together. I also wanted to make sure that the application was approachable by people new to Angular since I’ve never found overly complex applications great for learning new concepts.

The application initially started out small and was used in my AngularJS in 60-ish Minutes video on YouTube but has gradually had more and more features added to it and will continue to be enhanced over time. It’s used in a new “end-to-end” instructor-led training course my company wrote for AngularJS as well as in some video courses that will be coming out. Here’s a quick look at what the application home page looks like:


image

In this post I’m going to provide an overview about how the application is organized, back-end options that are available, and some of the features it demonstrates. I’ve already written about some of the features so if you’re interested check out the following posts:

 

Two versions of the application are available on Github including a “standard” version that uses out-of-the-box AngularJS features and a custom version that provides custom routing and dynamic loading of controller scripts:

CustomerManagerStandard:  https://github.com/DanWahlin/CustomerManagerStandard

CustomerManager with Custom Routing: https://github.com/DanWahlin/CustomerManager

 

Key Features


The Customer Manager application certainly doesn’t cover every feature provided by AngularJS but does provide insight into several key areas. Here are a few of the features it demonstrates with information about the files to look at if you want more details:

  1. Using factories and services as re-useable data services (see the app/customersApp/services folder)
  2. Creating custom directives (see the app/customersApp/directives and app/wc.directives/directives folder)
  3. Custom paging (see app/views/customers/customers.html and app/customersApp/controllers/customers/customersController.js)
  4. Custom filters (see app/customersApp/filters)
  5. Showing custom modal dialogs with a re-useable service (see app/customersApp/services/modalService.js)
  6. Making Ajax calls using a factory (see app/customersApp/services/customersService.js)
  7. Using Breeze to retrieve and work with data (see app/customersApp/services/customersBreezeService.js). Switch the application to use the Breeze factory by opening app/customersApp/config.js and changing the useBreeze property to true.
  8. Intercepting HTTP requests to display a custom overlay during Ajax calls (see app/wc.directives/directives/wcOverlay.js)
  9. Custom animations using the GreenSock library (see app/customersApp/animations/listAnimations.js)
  10. Creating custom AngularJS animations using CSS (see Content/customersApp/animations.css)
  11. JavaScript patterns for defining controllers, services/factories, directives, filters, and more (see any JavaScript file in the app folder)
  12. Card View and List View display of data (see app/customersApp/views/customers/customers.html and app/customersApp/controllers/customers/customersController.js)
  13. Using AngularJS validation functionality (see app/customersApp/views/customerEdit.html, app/customersApp/controllers/customerEditController.js, and app/customersApp/directives/wcUnique.js)
  14. Nesting controllers
  15. More…

Application Structure

 

The structure of the application is shown to the right. The  homepage is index.html and is located at the root of the application folder. It defines where application views will be loaded using the ng-view directive and includes script references to AngularJS, AngularJS routing and animation scripts, plus a few others located in the Scripts folder and to custom application scripts located in the app folder.

image

 

The app folder contains all of the key scripts used in the application. There are several techniques that can be used for organizing script files but after experimenting with several of them I decided that I prefer content organized by module name (customersApp and wc.directives are examples of module folder names). Within each module folder I follow a convention such as controllers, views, services, etc. Individual features are identified within a convention folder by using additional subfolders such as customers and orders. Doing that helps me find things a lot faster due to mixing the convention/feature approach.

I’m a huge believer in having some conventions in place especially when it comes to team development. Having managed several development teams over the years I learned that consistency across projects is good since people come and go on teams and taking that approach allows files to be categorized and located easily (such as controllers and services). If you’re new to an app (a new hire, production support, a contractor, etc.) and are given a pure feature-based folder structure to work with it can be challenging to find things if you don’t know the app features well since whoever created the folder structure did it based on their way of thinking about the app. If some convention is mixed in with the features it becomes much easier to find things in my opinion and it makes it easier to understand multiple projects – not just one. On the other hand, going with a pure convention-based approach causes challenges with large applications since a controllers folder could have a ton of files in it which is why I like to segregate things by module/convention/feature.

There are MANY different opinions on this so my recommendation is to go with whatever works best for you. I’m definitely not saying this is “the way”…this is my way. Anyone who says, “You’re doing it wrong!” should be ignored because in my experience these are generally the type of close-minded people you run into who aren’t willing to take time to consider alternatives to their approach. Contrary to what some people think, there is no “one right way” to organize scripts and files. As long as the scripts make it down to the client properly (you’ll likely minify and concatenate them anyway to reduce bandwidth and minimize HTTP calls so the structure is irrelevant to the browser), the way you organize them is completely up to you. Here’s what I ended up doing for this application:

  1. Animation code for some custom animations is located in the app/customersApp/animations folder. In addition to AngularJS animations (which are defined using CSS in Content/animations.css), it also animates the initial customer data load using a 3rd party script called GreenSock.
  2. Controllers are located in the app/customersApp/controllers folder. Some of the controllers are placed in subfolders based upon the their feature/functionality while others are placed at the root of the controllers folder since they’re more generic:


    image

  3. The directives folder contains the custom directives created for the application. Directives that can be used across projects are placed in the wc.directives/directives folder which represents the module/convention approach. 
  4. The filters folder (app/customersApp/filters) contains the custom filters created for the application that filter city/state and product information.
  5. The partials folder contains partial views. This includes things like modal dialogs used in the application.
  6. The services folder contains AngularJS factories and services used for various purposes in the application. Most of the scripts in this folder provide data/Ajax functionality. Two types of services exist to send and retrieve data to/from a RESTful service. The application uses $http by default but can be switched to use BreezeJS (an alternative way to work with data) by updating the config.js file.
  7. The views folder contains the different views used in the application. Like the controllers folder, the views are organized into subfolders based on their functionality:

image

 

Back-End Technologies


The Customer Manager application (grab it from Github) provides two different options on the back-end including ASP.NET Web API and Node.js so you'll want to select one of them in order to run the application. The ASP.NET Web API back-end uses C# and Entity Framework for data access and stores data in SQL Server (LocalDb). The other option on the back-end is Node.js, Express, and MongoDB.

 

Using the ASP.NET Web API Back-End Option

To run the application using ASP.NET Web API/SQL Server back-end open the .sln file at the root of the project in Visual Studio 2012 or higher (the free Visual Studio 2013 Community Edition version is fine). Press F5 and a browser will automatically launch and display the application. Under the covers, Entity Framework code first is used to create the database dynamically.

 

Using the Node.js Back-End Option

To run the application using the Node.js/MongoDB back-end follow the steps listed in the readme on the Github site.

 

Front-End Technologies


The Customer Manager application uses the following frameworks and libraries on the front-end:

  1. AngularJS (with the ngRoute and ngAnimation modules)
  2. Bootstrap
  3. Angular UI BootStrap
  4. GreenSock Animations
  5. BreezeJS (optional)

 

Optional

 

The application uses native AngularJS $http by default to make calls back to the server. However, by going to app/customersApp/services/config.js you can switch from using $http to using BreezeJS (a very cool client-side data management library). When using BreezeJS you’ll also want to include Breeze Angular Service  (the script is already loaded in index.html to keep things simple). For more details on what BreezeJS is all about check out my previous post.

  1. BreezeJS 
  2. Breeze Angular Service

 

Application Views


The application has several views designed to cover different aspects of AngularJS from editing data to displaying, paging, and filtering data. Here are the main views:

 

Customers View

This view provides multiple views of customer data (Card View and List View), supports paging, allows customers to be added or removed, and provides filtering functionality.

Card View (app/customersApp/views/customers/customers.html)

This view displays customer information and allows customers to be edited (by clicking their name), deleted (by clicking the X), or their orders to be viewed.


image

 

List View (app/customersApp/views/customers/customers.html)


This view displays customer information in a standard list type of view.


 image

 

Login View (app/customersApp/views/login.html)


This view allows the user to login. Security isn’t officially checked on the server for this demo as it just returns a boolean true value but the client-side does have security functionality built-in to show how that could be integrated with AngularJS, how events can be broadcast and handled, and more. Keep in mind that in a “real” application every secured resource on the server would have to be checked for the proper security credentials regardless of what data or information the client has.


image


 

Customer Edit View (app/customersApp/views/customers/customerEdit.html)


This view adds some custom AngularJS validation including a custom directive (wcUnique.js) that ensures that the email address being added is unique.


image


Customer Orders View (app/customersApp/views/customers/customerOrders.html)


This view shows the orders for a specific customer. Orders can be sorted by clicking on the column headings.

image

 


Orders View (app/customersApp/views/orders/orders.html)

This view shows orders for all customers and supports paging, filtering, and sorting of the orders.

 

image


About View (app/customersApp/views/about.html)


There isn’t much to this view but I listed it for the sake of completeness.


image

 

Custom Directives


Three custom directives are currently included in the application:

  1. Unique value directive (app/customersApp/directives/wcUnique.js) – This directive ensures that email addresses entered on the customer edit view are unique. It makes a call back to a service and then calls ngModel.$setValidity() to handle showing or hiding an error message. A post on this directive can be read here.

    image

  2. Angular Overlay directive (app/wc.directives/directives/wcOverlay.js) – This directive intercepts XmlHttpRequest calls and displays a custom overlay (tracks AngularJS calls as well as jQuery). The directive is available in the application or as a stand-alone directive on Github.

    AngularOverlay Directive Example

  3. Menu highlighter directive (app/wc.directives/menuHighlighter.js). This directive is responsible for highlighting menu items as a user clicks on them.


    image


Custom Filters


The application includes two custom filters used to filter data in the customers and orders views:

  1. Name/City/State Filter (app/customersApp/filters/nameCityStateFilter.js)

    image

  2. Name/Product Filter (app/customersApp/filters/nameProductFilter.js)


    image

 

Conclusion

I’ll be enhancing the application even more over time and welcome contributions as well. Tony Quinn contributed the initial Node.js/MongoDB code (thanks Tony!) which is very cool to have as a back-end option and several other contributions have been made for testing and the initial version of the menuHighlighter directive. Access the standard application here and a version that has custom routing in it here. Additional information about the custom routing can be found in this post.

Onsite Developer Training: If your company is interested in onsite training on JavaScript, ES6, AngularJS, Node.js, C# or other technologies please email training@thewahlingroup.com for details about the classes that we offer.

comments powered by Disqus

12 Comments

  • I loaded this into a Tomcat env and the code has many case issues when it comes to pathing and finding resources.

  • By far the best AngularJs learning resource out there !! Dan, I have a question: I've tried to combine: AngularJs + RequireJs + AngularFire + Firebase, however I'm having problems, AngularFire generates an error saying that angular is not available. Have you tried and succeed on this?
    Thanks !

  • Thanks Dan. Very useful. Learning tons here.

  • Thank you very much.
    It is the one I have been googling for since last month.
    What a great article about angula,node and mongodb!!!

  • Victor:

    I haven't played with Firebase at this point (only looked at a few demos) so I'm not sure what might be causing that error. I'd recommend posting details about what you're seeing to Stackoverlow.com to see if anyone else has experienced that error.

    Dan

  • Mike,

    Out of the box the app is designed to run with either Web API or Node.js as mentioned above. If you're trying it in a different environment you may have to change paths and things - hard to say since it hasn't been tested/run in a Tomcat environment. It should be pretty straightforward to do though since all of the script references and resources are in index.html.

    Dan

  • I went through the eBook and got to the $RouteProvider section and then began getting errors. I researched the error and saw that the current version of AngularJS did not include route information and I need to add that script reference as well. I did this, but still I get a Module Injection error.

  • Andy:

    That's correct - they changed that with version 1.2. You'll see that in the sample app above. Make sure your module definition includes ngRoute. Sounds like you already included the angular routing script in your main page.

    var app = angular.module('yourApp', ['ngRoute']);

    See the following example from the app above (it includes other dependencies as well that you won't need):

    https://github.com/DanWahlin/CustomerManagerStandard/blob/master/CustomerManager/app/app.js

    Dan

  • Great intro to AngularJS.
    Keep up the good work.

  • how to solove IE compatibility issues ?

  • Hello Dan,
    Thanks for creating this wonderful tutorial. Heads up from a beginning node/express developer: the package.json file in the CustomerManager directory "pins" the express server to version 3.0.0 like so:

    {
    "name": "CustomerManager"
    , "version": "0.0.1"
    , "private": true
    , "dependencies": {
    "express": "3.0.0"
    , "jade": ">= 0.0.1"
    , "mongodb": ">= 0.9.7-3-5"
    , "mongoose": ">= 2.4.10"
    , "connect-mongodb": ">= 1.1.3"
    , "sprintf": "*"
    }
    }

    instead, it should be allowed to use the latest version of express 3.x.x as shown below:

    {
    "name": "CustomerManager"
    , "version": "0.0.1"
    , "private": true
    , "dependencies": {
    "express": ">= 3.0.0"
    , "jade": ">= 0.0.1"
    , "mongodb": ">= 0.9.7-3-5"
    , "mongoose": ">= 2.4.10"
    , "connect-mongodb": ">= 1.1.3"
    , "sprintf": "*"
    }
    }

    Otherwise express throws an error and will not start the app.

    Now the question: You have defined two services the modalService and the dialogService. Of the two, it seems like only the modalService is being used in the application, correct? Why have you included the dialogService then? I am confused. kindly explain.

    Thanks.

    Bharat

  • Hello,

    I have an error when I load AngularJSDemos with Visual Studio.

    Error 1

    The program d: \ TESTS ROAMING \ 2014 \ AngularJs Program \ AngularJSDemos \ AngularJSDemos \ obj \ x86 \ Debug \ WindowsApplication.exe 'does not contain a' Main 'method suitable for a static entry point D: \ TESTS ROAMING \ 2014 \ AngularJs Program \ AngularJSDemos \ AngularJSDemos \ CSC AngularJSDemos

    Ps help on this case.
    Thanks

Comments have been disabled for this content.