Sei sulla pagina 1di 11

This document explains how to set up an angular project.

Pre-requisites
1. Install node.js from https://nodejs.org/en/. This will install node.js and npm(Node Package
Manager). Once you successfully install node.js, try node and npm from a command line to verify
that its working.
2. Install git from https://git-scm.com/downloads. (bower requires git. Note that this is just git
binary , not any server)
3. Install grunt-cli, the command line interface for grunt. In a command prompt, run “npm install –g
grunt-cli”, to install grunt globally (-g). Grunt is a task runner. If you are from a java background,
you can compare it to maven which helps us in compile and build projects. There are lot of grunt
modules available which helps us in compile, minify, concat , build a javascript project.
4. Install bower, the web package manager. In a command prompt, run “npm install –g bower”, to
install bower globally. With bower we can download, install and update correct versions of
packages. The difference between bower and npm is how they handle dependencies. Npm creates
nested dependencies, a package having another dependency having another and so on. This
doesn’t matter for a build setup. But for actual front end, this creates problems, eg: two of the
package you use depends on jquery, so site will end up downloading jquery twice. Bower helps
here, as it maintain a flat dependency. The dependencies are not nested and is on user. So it can
be managed better.
5. Install Ruby Install and then , gem install compass. Follow
http://thesassway.com/beginner/getting-started-with-sass-and-compass. This is to compile sass
file to css. SASS is an object oriented way of writing css style sheets. Please read more at
http://sass-lang.com/guide

Project setup
1. Create a directory myApp
2. Create package.json inside the directory. Package.json is the project manifest file which defines
details like name of the application, version, author, license etc. It lists down the dependencies
needed for the project. If there are dependencies defined in a package.json , that can be
downloaded and installed by just using “npm install”.
Copy the below contents to the package.json file created. Note that it has two sets of
dependencies section. “dependencies” describe the actual code dependency , eg: angular; whereas
devDependencies are modules required to build and run the project, eg: grunt. We are not specifying
dependencies here, since we will use bower for that.
{
"author": "MicroFocus",
"name": "MyApp",
"version": "1.0.0",
"licenses": {
"text": "MIcroFocus. All rights reserved.",
"copyrightDate": "2016-2017"
},
"dependencies": {},
"devDependencies": {
"grunt": "~0.4.1",
"grunt-autoprefixer": "~0.4.0",
"grunt-bower-install": "~0.7.0",
"grunt-concurrent": "~0.4.1",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-connect": "~0.5.0",
"grunt-contrib-copy": "~0.4.1",
"grunt-contrib-cssmin": "~0.7.0",
"grunt-contrib-htmlmin": "~0.1.3",
"grunt-contrib-imagemin": "~0.3.0",
"grunt-contrib-jshint": "~0.7.1",
"grunt-contrib-uglify": "~0.2.0",
"grunt-contrib-watch": "~0.5.2",
"grunt-contrib-compass": "~0.7.2",
"grunt-newer": "~0.5.4",
"grunt-ngmin": "~0.0.2",
"grunt-rev": "~0.1.0",
"grunt-svgmin": "~0.2.0",
"grunt-usemin": "~2.0.0",
"grunt-html2js": "~0.1.3",
"jshint-stylish": "~0.1.3",
"load-grunt-tasks": "~0.2.0",
"time-grunt": "~0.2.1",
"karma-ng-scenario": "~0.1.0",
"grunt-karma": "~0.6.2",
"karma-script-launcher": "~0.1.0",
"karma-firefox-launcher": "~0.1.3",
"karma-chrome-launcher": "~0.1.2",
"karma-html2js-preprocessor": "~0.1.0",
"karma-jasmine": "~0.1.5",
"requirejs": "~2.1.11",
"karma-requirejs": "~0.2.1",
"karma-phantomjs-launcher": "~0.1.2",
"karma": "~0.10.9",
"karma-ng-html2js-preprocessor": "~0.1.0",
"grunt-ngdocs": "~0.2.1",
"grunt-war": "~0.2.6",
"grunt-ssh": "~0.11.1",
"grunt-protractor-runner": "~0.2.4",
"karma-coverage": "~0.2.1"
}
}

3. Create bower.json. Similar to package.json, this is the bower manifest file to list down the code
dependencies you need.
Copy the below content to your bower.json
{
"name": "MyApp",
"version": "1.0.0",
"dependencies": {
"angular": "^1.5.7",
"angular-ui-router": "^0.3.1",
"angular-bootstrap": "^1.3.3"
},
"devDependencies": {
"angular-mocks": "^1.5.7",
"angular-scenario": "^1.5.7"
}
}
4. Create another file .bowerrc . This file specifies where to download packages mentioned in the
bower.json. Copy the below contents to this file. This means that the dependencies will be
download to lib directory in the root folder of the project.
{
"directory": "lib"
}

5. Copy the GruntFile.js. This file specifies all grunt tasks required to build and run the project.
6. Copy build.config.js . This is a helper file for GruntFile and specifies the file locations and paths
required for the project.
7. Create a file .jshintrc . This is to do code quality check for the javascript files we have written.
You can add many more checks like below ones.
{
"browser": true,
"bitwise": true,
"camelcase": true,
"curly": true,
"eqeqeq": true,
"eqnull":true,
"expr":true,
"immed": true,
"indent": 4,
"latedef": true,
"laxbreak":true,
"newcap": true,
"noarg": true,
"quotmark": "single",
"regexp": true,
"undef": true,
"unused": "vars",
"strict": true,
"trailing": true,
"smarttabs": true,
"devel":true,
"globals": {
"angular": false
}
}

8. Once the above steps are completed, we can start installing the dependencies for the project.
Open a command prompt at the project folder root
a. Run “npm install”. This will download and install all dev dependencies specified in the
package.json
b. Run “bower install”. This will download and install all dependencies specified in the
bower.json.
9. Create two folders – src and test, to hold our source files and test files respectively.
Developing a small angular app
We will create a small app which has two links – Home and About that can open the respective pages.
1. Create index.html in src folder. This is the starting point of our app. Note the script blocks for
link and script in the head section. This will be filled with required js and css files during build.
This is useful as we don’t have to hardcode each css and js file we need in this file. If you want
to more about how this done, take a look at the “index” task in GruntFile.js

<!doctype html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>My App</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
<!-- compiled CSS --><% styles.forEach( function ( file ) { %>
<link rel="stylesheet" type="text/css" href="<%= file %>" /><% }); %>

<!-- compiled JavaScript --><% scripts.forEach( function ( file ) { %>


<script type="text/javascript" src="<%= file %>"></script><% }); %>

</head>

<body ng-app="myApp">
<!-- Add your site or application content here -->
This is my main page
<nav>
<ul>
<li>
<a href="#/home">

Home
</a>
</li>
<li>
<a href="#/about">

What is it?
</a>
</li>
</ul>
</nav>
<div ui-view="main"></div>

</body>
</html>

The main thing to note in the html is the body tag. The custom component “ng-app” specifies
that this is an angular app. Angular bootstraps when it sees ng-app in an html tag. You may also
specify ng-app at any other level, say a <div> tag. You can have multiple ng-apps in a page
parallel to each other, but not nested. This is useful if you are migrating your existing application
to angular, and want to do small steps at a time.

The application has two links Home and About which will open a Home and an About page.
The next main thing is another custom property to div tag named “ui-view”. This custom tag
provides routing for our angular app. This comes from the dependency we added – angular-ui-
route. This property will replace the div section with contents from various modules depending
on the url. For eg: if the url is /home, the div will contain the contents for home page. This type of
web apps which has only one full html, and replaces its content based on url changes is known as
SPA(Single Page Application).

2. Now we will write code for our angular app.


Create a file app.js inside src/app. This contains the main module we used to bootstrap the app
which is myApp. (Remember we added this in ng-app=”myApp”).
Create an angular module called myApp.
angular.module( 'myApp', [])

This will create an angular module called myApp. Note the second argument with []. This is used to pass
the dependent modules if any to this module.
Note: If you want to access this module in some other place, the syntax is almost
same. Use var myAppModule = angular.module( 'myApp'). The same method with dependency
argument is a getter.

Add a controller to the module created. The controller is the one who does actions required for the
page/module.

function AppController(){
}

angular.module( 'myApp', [])

.controller( 'AppCtrl', [AppController]);

We can directly append controller (or service or any such object) to the module using dot notation. The
syntax for defining a controller is similar to that of a module, only that it contains an additional param.

The syntax is .controller(‘CtrlName’, [dep1, dep2, …., function(dep1, dep2){}]);


The first argument is the name with which the Controller is referred in angular app. The second argument
is a list of dependencies , followed by a function which has all controller logic.

Note that in our controller we don’t have any dependencies, and we have just given the name of a
function AppController. We have defined that function at the top of controller definition.

Now, our app controller does not do anything great. The module will just route the app according to the
given urls. We have two pages Home and About. Lets add them.
There are many ways to write code for an angular app. One way is to write all controllers, all services, all
templates in its own folder. But another neat way is to write as modules/functionality. In this method, all
files – module, controller, services, template html etc for one functionality is grouped together. This way
provides us better re-use of modules to some other product. We will follow this approach.
Lets create our Home module. Create a folder src/app/home. Create the file home.js.

Create a Home module and controller.

function HomeController() {
'use strict';
}

angular.module( 'home', [
'ui.router'
])

.config(function config( $stateProvider ) {


'use strict';
$stateProvider.state( 'home', {
url: '/home',
views: {
'main': {
controller: 'HomeCtrl as HomeController',
templateUrl: 'home/home.tpl.html'
}
},
data:{ pageTitle: 'Home' }
});
})

.controller( 'HomeController',[HomeController] );

Noe that we have a new section .config after the module definition. This is the configuration block for a
module. We will define the /home route in the configuration block. For this we need an object
$stateProvider. This object is given by another third party angular package called angular-ui-router. We
have added the module provided by this pacakage “ui.router” as a dependency to the home module. Once
a module is added as dependency, we can access all objects exposed in the module by providing it as
dependency to the function block where it is required.

The /home URL is configured with controller as HomeController, and the template html from
homw.tpl.html. Note the “controller as” syntax given - 'HomeCtrl as HomeController'. This enables us to
write the controller function without passing $scope variable. This also helps us to write a clean javscript
function without using $scope, which means it will be angular2 safe. We will able to use the same
function in angular2.

To understand more on Controller As Syntax, read https://toddmotto.com/digging-into-angulars-


controller-as-syntax/

NOTE: Explaining routing concepts is beyond the scope of this document. Please read
https://scotch.io/tutorials/angular-routing-using-ui-router
https://angular-ui.github.io/ui-router/
Now, we need to create the template html for our home view. Create a file src/app/home/home.tpl.html
Add the following contents.

<div>
This is home
</div>

Lets add our second module About in the same way. Create a directory src/app/about for the about
functionality. Create src/app/about/about.js.
Define the about module and controller.

function AboutController( ) {
'use strict';

var self = this;


// This is simple a demo for UI Boostrap.
self.about = "This is the about page for About window, which tells something about
it";
}

angular.module( 'about', [
'ui.router'
])

.config(function config( $stateProvider ) {


'use strict';
$stateProvider.state( 'about', {
url: '/about',
views: {
'main': {
controller: 'AboutController as AboutCtrl',
templateUrl: 'about/about.tpl.html'
}
}
});
})

.controller( 'AboutController', [AboutController] );

In the controller we have defined a variable about. This variable is attached to the scope and so we will be
able to access it from the template html.

Add the template html. Create src/app/about/about.tpl.html.


<div>
<span ng-bind="AboutCtrl.about"></span>
</div>
See how we can bind the variable to html. We can use the “AboutCtrl.” for all variables in html. This is
facilitated by the Controller As syntax.
3. We have created a small app. Lets see it in action now. Open a command prompt at the root of
project folder. Run “grunt serve”. This command will build and serve the app in browser. Your
app should automatically open in Chrome. You should be able to click the Home and About links.
The URLs should change accordingly displaying the respective html.

Fetching some data from the backend.


Our application is useless if it cannot fetch data from some backend and display it. So let’s see how this is
done.
In angular, data is provided by a Service layer. The data can be hardcoded or dynamic from some other
service. We will add a service to our home page to get some data from a REST call.

Create a service file at src/app/home/home.service.js

function HomeService(){
'use strict';
var self = this;

angular.module('home')

.service('HomeService', [HomeService]);

The definition of a service is similar to that of a controller, except that we use “service”.

Lets add some logic to this. We will add a method to this service to fetch a list of stocks data from a
REST call.
Modify the HomeService function.

function HomeService($http){
'use strict';

var self = this;

self.getData = function(){
return $http.get('/api/stocks');
};

angular.module('home')
.service('HomeService', ['$http', HomeService]);

Note that we have used the same home module as a getter here.

Note the introduction of $http as dependency to the service, and correspondingly to the HomeService
function. $http is an object provided by angular framework to issue ajax calls.
To learns more about $http, read http://www.w3schools.com/angular/angular_http.asp

Now that we have a service let’s use it in the home page. Modify home controller function to have the
below
self.stocks = [];

HomeService.getData().then(function(response) {
self.stocks = response.data;
});

We added a variable stocks which is exposed by angular scope. This variable is populated with the data
from the service.
Modify the home tpl to contain

<div ng-repeat="stock in HomeCtrl.stocks">


<div>
<div class="col-md-3">
<span ng-bind="stock.name">{{stock.name}}</span>
<span ng-bind="stock.price">$17.11</span>

</div>
</div>
</div>

This will just print the stock options.

Now try grunt serve again from command prompt. Once the page is up, press F12 to get the browser dev
toolbar. You can see HTTP 404 error for our REST call. The REST call does not exist yet.

In normal development, these REST calls will be provided by the product backend. One beauty of client
side development is that we don’t have to wait for the actual backend to be ready to develop and test our
UI. The only thing to be finalized is the REST call URL, parameters and return data structure. Once we
have this, we can use a simple node server to simulate our REST call which will send some sample data.
Setting up a Node server
Create a file at project root as index.js. Add code to start a node server.
var express = require('express'),
bodyParser = require('body-parser');

var app = new express();

app.use(express.static(__dirname + '/'));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

app.get('/api/stocks', function(req, res) {


res.json([
{id: "TWTR", name: "Twitter Inc", price: 80, previous: 70},
{id: "FB", name: "Facebook Inc", price: 54, previous: 58},
{id: "GOOG", name: "Google Inc", price: 105, previous: 100}
]);
});

var server = app.listen(3000, function () {


console.log('Example app listening at http://localhost:3000');

Note the usage of require(‘express’). Express is a node addon(library) which provides api to create a
server. The server we created is listening on port 3000.
We have defined the REST call which will return sample stocks data.

Try to start this server. Open a command prompt at project root. Run “node index.js”. You will see
exception saying “express” not defined. The reason is we have used some node addons which are not
installed yet to our node_modules directory.
To correct this, run the following: “npm install express –save-dev” and then “npm install body-parser –
save-dev”. The –save-dev option automatically adds this dependency to our package.json.

Now, Try the server again – node index.js. the server is up and running at port 3000.

Now, we have one problem. Our grunt server is running at a static web server at localhost:9000 and node
server is running at localhost:3000. By browser single origin policy we cannot make calls between
different origins (domain:port). So we need a task which can start our node server and web app at a single
server instance which is similar to our production environment.
We already have another grunt task configured in our GruntFile for this purpose.
Run “grunt serveExpress”. Now access the url from http://localhost:3000. Note that if you change you
files, it will automatically compiled. But you still need to refresh to see the change. Take this as a task to
learn some grunt task 
Extra stuff

We have not used any css stylings in this sample. This setup is configured to use sass. Try to add
some sass style sheets in each module and style the html using them.

The setup is configured for jasmine, karma and protractor. Write UT , e2e test cases.

Open GruntFile and see the tasks exposed. Try them.

Potrebbero piacerti anche