13 min read

This article by Jonathan Spratley, the author of book, Learning Yeoman, covers the steps of how to create an AngularJS project and previewing our application.

(For more resources related to this topic, see here.)

Anatomy of an Angular project

Generally in a single page application (SPA), you create modules that contain a set of functionality, such as a view to display data, a model to store data, and a controller to manage the relationship between the two. Angular incorporates the basic principles of the MVC pattern into how it builds client-side web applications.

The major Angular concepts are as follows:

  • Templates : A template is used to write plain HTML with the use of directives and JavaScript expressions
  • Directives : A directive is a reusable component that extends HTML with the custom attributes and elements
  • Models : A model is the data that is displayed to the user and manipulated by the user
  • Scopes : A scope is the context in which the model is stored and made available to controllers, directives, and expressions
  • Expressions : An expression allows access to variables and functions defined on the scope
  • Filters : A filter formats data from an expression for visual display to the user
  • Views : A view is the visual representation of a model displayed to the user, also known as the Document Object Model (DOM)
  • Controllers : A controller is the business logic that manages the view
  • Injector : The injector is the dependency injection container that handles all dependencies
  • Modules : A module is what configures the injector by specifying what dependencies the module needs
  • Services : A service is a piece of reusable business logic that is independent of views
  • Compiler : The compiler handles parsing templates and instantiating directives and expressions
  • Data binding : Data binding handles keeping model data in sync with the view

Why Angular?

AngularJS is an open source JavaScript framework known as the Superheroic JavaScript MVC Framework, which is actively maintained by the folks over at Google. Angular attempts to minimize the effort in creating web applications by teaching the browser’s new tricks. This enables the developers to use declarative markup (known as directives or expressions) to handle attaching the custom logic behind DOM elements.

Angular includes many built-in features that allow easy implementation of the following:

  • Two-way data binding in views using double mustaches {{ }}
  • DOM control for repeating, showing, or hiding DOM fragments
  • Form submission and validation handling
  • Reusable HTML components with self-contained logic
  • Access to RESTful and JSONP API services

The major benefit of Angular is the ability to create individual modules that handle specific responsibilities, which come in the form of directives, filters, or services. This enables developers to leverage the functionality of the custom modules by passing in the name of the module in the dependencies.

Creating a new Angular project

Now it is time to build a web application that uses some of Angular’s features. The application that we will be creating will be based on the scaffold files created by the Angular generator; we will add functionality that enables CRUD operations on a database.

Installing the generator-angular

To install the Yeoman Angular generator, execute the following command:

$ npm install -g generator-angular

For Karma testing, the generator-karma needs to be installed.

Scaffolding the application

To scaffold a new AngularJS application, create a new folder named learning-yeoman-ch3 and then open a terminal in that location. Then, execute the following command:

$ yo angular –coffee

This command will invoke the AngularJS generator to scaffold an AngularJS application, and the output should look similar to the following screenshot:

Understanding the directory structure

Take a minute to become familiar with the directory structure of an Angular application created by the Yeoman generator:

  • app: This folder contains all of the front-end code, HTML, JS, CSS, images, and dependencies:
    • images: This folder contains images for the application
    • scripts: This folder contains AngularJS codebase and business logic:
      • app.coffee: This contains the application module definition and routing
      • controllers: Custom controllers go here:
        • main.coffee: This is the main controller created by default
      • directives: Custom directives go here
      • filters: Custom filters go here
      • services: Reusable application services go here
    • styles: This contains all CSS/LESS/SASS files:
      • main.css: This is the main style sheet created by default
    • views: This contains the HTML templates used in the application
      • main.html: This is the main view created by default
    • index.html: This is the applications’ entry point
  • bower_components: This folder contains client-side dependencies
  • node_modules: This contains all project dependencies as node modules
  • test: This contains all the tests for the application:
    • spec: This contains unit tests mirroring structure of the app/scripts folder
    • karma.conf.coffee: This file contains the Karma runner configuration
  • Gruntfile.js: This file contains all project tasks
  • package.json: This file contains project information and dependencies
  • bower.json: This file contains frontend dependency settings

The directories (directives, filters, and services) get created when the subgenerator is invoked.

Configuring the application

Let’s go ahead and create a configuration file that will allow us to store the application wide properties; we will use the Angular value services to reference the configuration object.

Open up a terminal and execute the following command:

$ yo angular:value Config

This command will create a configuration service located in the app/scripts/services directory. This service will store global properties for the application.

For more information on Angular services, visit http://goo.gl/Q3f6AZ.

Now, let’s add some settings to the file that we will use throughout the application. Open the app/scripts/services/config.coffee file and replace with the following code:

‘use strict’ angular.module(‘learningYeomanCh3App’).value(‘Config’, Config =

baseurl: document.location.origin sitetitle: ‘learning yeoman’

sitedesc: ‘The tutorial for Chapter 3’ sitecopy: ‘2014 Copyright’

version: ‘1.0.0’

email: ‘[email protected]’ debug: true

feature:

title: ‘Chapter 3’

body: ‘A starting point for a modern angular.js application.’ image: ‘http://goo.gl/YHBZjc’

features: [

title: ‘yo’

body: ‘yo scaffolds out a new application.’ image: ‘http://goo.gl/g6LO99’

,

title: ‘Bower’

body: ‘Bower is used for dependency management.’ image: ‘http://goo.gl/GpxBAx’

,

title: ‘Grunt’

body: ‘Grunt is used to build, preview and test your project.’ image: ‘http://goo.gl/9M00hx’

]

session:

authorized: false user: null

layout:

header: ‘views/_header.html’ content: ‘views/_content.html’ footer: ‘views/_footer.html’

menu: [

title: ‘Home’, href: ‘/’

,

title: ‘About’, href: ‘/about’

,

title: ‘Posts’, href: ‘/posts’

]

)

The preceding code does the following:

  • It creates a new Config value service on the learningYeomanCh3App module
  • The baseURL property is set to the location where the document originated from
  • The sitetitle, sitedesc, sitecopy, and version attributes are set to default values that will be displayed throughout the application
  • The feature property is an object that contains some defaults for displaying a feature on the main page
  • The features property is an array of feature objects that will display on the main page as well
  • The session property is defined with authorized set to false and user set to null; this value gets set to the current authenticated user
  • The layout property is an object that defines the paths of view templates, which will be used for the corresponding keys
  • The menu property is an array that contains the different pages of the application

Usually, a generic configuration file is created at the top level of the scripts folder for easier access.

Creating the application definition

During the initial scaffold of the application, an app.coffee file is created by Yeoman located in the app/scripts directory. The scripts/app.coffee file is the definition of the application, the first argument is the name of the module, and the second argument is an array of dependencies, which come in the form of angular modules and will be injected into the application upon page load.

The app.coffee file is the main entry point of the application and does the following:

  • Initializes the application module with dependencies
  • Configures the applications router

Any module dependencies that are declared inside the dependencies array are the Angular modules that were selected during the initial scaffold. Consider the following code:

‘use strict’ angular.module(‘learningYeomanCh3App’, [

‘ngCookies’,

‘ngResource’,

‘ngSanitize’,

‘ngRoute’

])

.config ($routeProvider) ->

$routeProvider

.when ‘/’,

templateUrl: ‘views/main.html’ controller: ‘MainCtrl’

.otherwise redirectTo: ‘/’

The preceding code does the following:

  • It defines an angular module named learningYeomanCh3App with dependencies on the ngCookies, ngSanitize, ngResource, and ngRoute modules
  • The .config function on the module configures the applications’ routes by passing route options to the $routeProvider service

Bower downloaded and installed these modules during the initial scaffold.

Creating the application controller

Generally, when creating an Angular application, you should define a top-level controller that uses the $rootScope service to configure some global application wide properties or methods. To create a new controller, use the following command:

$ yo angular:controller app

This command will create a new AppCtrl controller located in the app/scripts/controllers directory.

file and replace with the following code:

‘use strict’ angular.module(‘learningYeomanCh3App’)

.controller(‘AppCtrl’, ($rootScope, $cookieStore, Config) ->

$rootScope.name = ‘AppCtrl’ App = angular.copy(Config)

App.session = $cookieStore.get(‘App.session’)

window.App = $rootScope.App = App)

The preceding code does the following:

  • It creates a new AppCtrl controller with dependencies on the $rootScope, $cookieStore, and Config modules
  • Inside the controller definition, an App variable is copied from the Config value service
  • The session property is set to the App.session cookie, if available

Creating the application views

The Angular generator will create the applications’ index.html view, which acts as the container for the entire application. The index view is used as the shell for the other views of the application; the router handles mapping URLs to views, which then get injected to the element that declares the ng-view directive.

Modifying the application’s index.html

Let’s modify the default view that was created by the generator. Open the app/index.html file, and add the content right below the following HTML comment:

The structure of the application will consist of an article element that contains a header,<article id=”app”

<article id=”app” ng-controller=”AppCtrl” class=”container”>

  <header id=”header” ng-include=”App.layout.header”></header>

  <section id=”content” class=”view-animate-container”>

    <div class=”view-animate” ng-view=””></div>

  </section>

  <footer id=”footer” ng-include=”App.layout.footer”></footer>

</article>

In the preceding code:

  • The article element declares the ng-controller directive to the AppCtrl controller
  • The header element uses an ng-include directive that specifies what template to load, in this case, the header property on the App.layout object
  • The div element has the view-animate-container class that will allow the use of CSS transitions
  • The ng-view attribute directive will inject the current routes view template into the content
  • The footer element uses an ng-include directive to load the footer specified on the App.layout.footer property

Use ng-include to load partials, which allows you to easily swap out templates.

Creating Angular partials

Use the yo angular:view command to create view partials that will be included in the application’s main layout. So far, we need to create three partials that the index view (app/index.html) will be consuming from the App.layout property on the $rootScope service that defines the location of the templates.

Names of view partials typically begin with an underscore (_).

Creating the application’s header

The header partial will contain the site title and navigation of the application. Open a terminal and execute the following command:

$ yo angular:view _header

This command creates a new view template file in the app/views directory.

Open the app/views/_header.html file and add the following contents:

<div class="header">
  <ul class="nav nav-pills pull-right">
    <li ng-repeat="item in App.menu" 
      ng-class="{'active': App.location.path() === item.href}">
      <a ng-href = "#{{item.href}}"> {{item.title}} </a>
    </li>
  </ul>
  <h3 class="text-muted"> {{ App.sitetitle }} </h3>
</div>

The preceding code does the following:

  • It uses the {{ }} data binding syntax to display App.sitetitle in a heading element
  • The ng-repeat directive is used to repeat each item in the App.menu array defined on $rootScope

Creating the application’s footer

The footer partial will contain the copyright message and current version of the application. Open the terminal and execute the following command:

$ yo angular:view _footer

This command creates a view template file in the app/views directory.

Open the app/views/_footer.html file and add the following markup:

<div class=”app-footer container clearfix”>

    <span class=”app-sitecopy pull-left”>

      {{ App.sitecopy }}

    </span>

    <span class=”app-version pull-right”>

      {{ App.version }}

    </span>

</div>

The preceding code does the following:

  • It uses a div element to wrap two span elements
  • The first span element contains data binding syntax referencing App.sitecopy to display the application’s copyright message
  • The second span element also contains data binding syntax to reference App.version to display the application’s version

Customizing the main view

The Angular generator creates the main view during the initial scaffold. Open the app/views/main.html file and replace with the following markup:

<div class=”jumbotron”>

    <h1>{{ App.feature.title }}</h1>

    <img ng-src=”{{ App.feature.image  }}”/>

      <p class=”lead”>

      {{ App.feature.body }}

      </p>

  </div>  

  <div class=”marketing”>

  <ul class=”media-list”>

        <li class=”media feature” ng-repeat=”item in App.features”>

       <a class=”pull-left” href=”#”>

          <img alt=”{{ item.title }}”

                      src=”http://placehold.it/80×80″

                      ng-src=”{{ item.image }}”

           class=”media-object”/>

       </a>

       <div class=”media-body”>

          <h4 class=”media-heading”>{{item.title}}</h4>

          <p>{{ item.body }}</p>

       </div>

        </li>

  </ul>

</div>

The preceding code does the following:

  • At the top of the view, we use the {{ }} data binding syntax to display the title and body properties declared on the App.feature object
  • Next, inside the div.marketing element, another div element is declared with the ng-repeat directive to loop for each item in the App.features property
  • Then, using the {{ }} data binding syntax wrapped around the title and body properties from the item being repeated, we output the values

Previewing the application

To preview the application, execute the following command:

$ grunt serve

Your browser should open displaying something similar to the following screenshot:

Download the AngularJS Batarang (http://goo.gl/0b2GhK) developer tool extension for Google Chrome for debugging.

Summary

In this article, we learned the concepts of AngularJS and how to leverage the framework in a new or existing project.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here