background
AngularJS is a structural framework for dynamic web apps. It lets you extend HTML’s syntax to express your application’s components in a clear and concise manner.
AngularJS is what HTML would have been, had it been designed for applications. It attempts to minimize the mismatch between document centric HTML and what an application needs by creating new HTML constructs.
AngularJS teaches the browser new syntax through constructs called directives. With the AngularJS framework you can build a versatile application using custom declarative elements with basic application features done for you out of the box.
Model View Controller(MVC) is a software design pattern for developing web applications. In this pattern, different features are broken into components to separate responsibilities. The model contains the data and logic, the view contains the visual layout and presentation, while the controller connects the two.
In AngularJS, the MVC pattern is implemented in JavaScript and HTML. The view is defined in HTML while the model and controller are implemented in JavaScript.
This tutorial focuses on AngularJS 1.x application codes and unit test.
The project code of this tutorial can be downloaded from Github
Application
This topic uses the latest Angular.js package ‘angular@1.5.8’
Scaffolding
Yeoman is a generic scaffolding system allowing the creation of any kind of app. Yeoman by itself doesn’t make any decisions. Every decision is made by generators which are basically plugins in the Yeoman environment.
Setting up Yeoman
npm install -g yo
Install Fountain Generator
npm i -g generator-fountain-webapp
Generate a web application step by step (generated project includes features: webpack, angular1, gulp, … you can find the details in file “.yo-rc.json” in project root)
yo fountain-webapp
Run
npm install -g gulp-cli
gulp serve
start up the server for testing locally
gulp
build and package the project codes into distribution.
How to cancel eslint syntax check: If you use Webpack, comment the preLoader part of the conf. If not, comment the eslint part of gulp_tasks/scripts.js.
Architectures
Project Architecture
The architecture of a angular.js project:
JavaScript-Project
|- conf/
| |- gulp.conf.js
| |- karma.conf.js
| |- webpeak.conf.js
| |- .../
|- dist/
| |- index.html
| |- vendor-xxxxxx.js
| |- app-xxxxxx.js
| |- index-xxxxxx.css
| |- .../
|- gulp_tasks/
|- node_modules/
| |- .../
|- src/
| |- ../
|- .yo-rc.json
|- gulpfile.js
|- package.json
|/
Application Architecture
The architecture of an Angular.js application:
Angularjs-Application
|- app/
| |- navigation.js
| |- navigation.spec.js
| |- login/
| | |- implicit-grant.html
| | |- implicit-grant.js
| | |- implicit-grant.spec.js
| | |- .../
| |- .../
|- components/
| |- message-component.js
| |- message-component.spec.js
| |- .../
|- services/
| |- oauth2-service.js
| |- oauth2-service.spec.js
| |- .../
|- index.html
|- index.js
|- index.css
|- index.spec.js
|- .eslintrc.js
|/
Angularjs Codes
Require Angular Modules
Import angular modules into the application, then you can add the module dependencies into your angular module.
var angular = require('angular');
require('angular-route');
require('angular-resource');
Create an Angular Module
Create an Angular module and add it’s module dependencies
angular.module('app', ['ngRoute', 'ngResource'])
Create Angular Artifacts
Create independent files for every artifacts in Angular application, for example factory, service and controller. Then load them into an entry file using require
.
var yaasOAuth2 = require('./services/yaas-oauth2');
...
angular
.module(app, ['ngRoute', 'ngResource'])
.factory('YaaSOAuth2', yaasOAuth2)
Controller
Controllers are the behavior behind the DOM elements. AngularJS lets you express the behavior in a clean readable form without the usual boilerplate of updating the DOM, registering callbacks or watching model changes.
Data-binding is an automatic way of updating the view whenever the model changes, as well as updating the model whenever the view changes. This is awesome because it eliminates DOM manipulation from the list of things you have to worry about.
Define a navigation controller
angularModule
.controller('NavigationController', ['$scope', function($scope) {
$scope.navigations = [
{title: "implicit grant", url: "#/implicit-grant"},
{title: "client credentials", url: "#/client-credentials"},
{title: "password credentials", url: "#/password-credentials"}
];
}]);
Use the controller in HTML, and add the Data-binding in the HTML elements, so you will obtain a navigation list
<body ng-app="app">
<div ng-controller="NavigationController">
<ul class="navigation">
<li ng-repeat="navigation in navigations">
<a href=""></a>
</li>
</ul>
</div>
...
Reusable Components
A Component is a special kind of directive that uses a simpler configuration which is suitable for a component-based application structure.
angularModule
.component('messageComponent', {
template: require('./message-component.html'),
controller: function MessageComponentController() {
this.title = "This is response from YaaS server";
},
bindings: {
message: '='
}
})
Use the component in the HTML, the variable response
that passes value to the property message
of messageComponent
is from parent controller’s $scope
<h3>Response</h3>
<message-component message="response"></message-component>
Angular Services
Angular services are substitutable objects that are wired together using dependency injection (DI). You can use services to organize and share code across your app.
Angular services are:
- Lazily instantiated – Angular only instantiates a service when an application component depends on it.
- Singletons – Each component dependent on a service gets a reference to the single instance generated by the service factory.
Define the implementation of factory service that can be used by other controllers
angularModule
.factory('YaaSOAuth2', ['$resource', function($resource) {
return $resource('https://api.beta.yaas.io/hybris/oauth2/v1/token',
{},
{
authorize: {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
transformRequest : function(obj){
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
}
}
}
);
}]);
Use the service’s object in Controller
module.exports = ['$scope', 'YaaSOAuth2', function($scope, YaaSOAuth2) {
...
YaaSOAuth2.authorize(credentials, function(response) {
$scope.credentials = credentials;
$scope.response = response;
});
}];
Test
Karma is a JavaScript command line tool that can be used to spawn a web server which loads your application’s source code and executes your tests. You can configure Karma to run against a number of browsers, which is useful for being confident that your application works on all browsers you need to support. Karma is executed on the command line and will display the results of your tests on the command line once they have run in the browser.
Karma is a NodeJS application, and should be installed through npm. Full installation instructions are available on the Karma website. In this topic it has been integrated in fountain automatically.
Unit Test
Jasmine is a behavior driven development framework for JavaScript that has become the most popular choice for testing Angular applications. Jasmine provides functions to help with structuring your tests and also making assertions. As your tests grow, keeping them well structured and documented is vital, and Jasmine helps achieve this.
Define the unit test file ‘src/app/navigation.spec.js’
var angular = require('angular');
require('angular-mocks');
var Navigation = require('./navigation');
describe('navigation', function () {
beforeEach(function () {
angular
.module('app', [])
.controller('NavigationController', Navigation);
angular.mock.module('app');
});
it('show the navigations in index', angular.mock.inject(function ($controller) {
var $scope = {};
$controller('NavigationController', {$scope: $scope});
expect($scope.navigations.length).toEqual(3);
}));
});
ESLint
ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code, with the goal of making code more consistent and avoiding bugs. It’s used in this project.
To change the rules in ESLint, you can modify the eslintConfig
field in a package.json
file or an .eslintrc.*
file in your project.
Package & Deploy
Use the gulp command gulp default
to clean and build the source codes into distribution folder.
Then you can deploy the application on to one of the Cloud Foundry servers.
Define the configuration file manifest.yml for cloud foundry
---
applications:
- name: <your-app-name>
path: dist
random-route: true
memory: 64M
Login cloud foundry based server
$ cf login [-a API_URL] [-u USERNAME] [-p PASSWORD] [-o ORG] [-s SPACE]
Then use the command cf push
to deploy the application.
Comments