On Github cjus / AngularPresentation
Presented by Carlos Justiniano / @cjus / Presentation version: 0.5
This presentation doesn't all of Angular. In fact, many parts were intentionaly omitted for brevity.
This is an interactive presentation, built on top of Reveal.js and featuring AngularJS.
This presentation is built entirely on HTML, CSS and JavaScript to run inside of your web browser.
The presentation is mobile and tablet friendly and the entire presentation is available on Github at the link shown on this page
All of the sample code featured is available in the samplecode folder within the project
If you find any issue with this presentation drop me an email or better yet, issue a pull request
Before AJAX platforms like PHP, Python/Django and Ruby/Rails were used to help render web front-ends
That worked great but required pages to be refreshed to see any data updates.
By eliminating the need for full-page refreshes, AJAX marked an important shift in the development of the web.
Web applications became more responsive and increasingly more ambitious applications were being built.
Front-ends started relying less on backend servers as more application logic moved into the front-end.
This benefitted the backend because rendering, logic and computation could be distributed to user machines allowing backends to more easily scale.
As code moved into the front-end and front-ends became richer, developers found they needed ways to handle the increased front-end code. They were forced to consider how large applications are built using software libraries and frameworks and bring some of that native and server goodness to front-end development.
They begin developing open-source front-end web frameworks with names like: Backbone, Ember, Knockout and Angular.
Today there are no lack of choices regarding framework. However, Angular has made a name for itself and many of the developers I meet are genuinely excited about it.
Frameworks like Backbone, Ember and Knockout are great for building single page web applications.
However, as an application grows older frameworks require developers to do more work to keep their applications maintanable.
Angular stands apart from other frameworks in that it is first and foremost about unlocking the potential of HTML.
Angular embraces HTML and extends it in ways which feel natural and uncontrived.
In fact, starting Angular developers eventually realize that if HTML and the DOM were more evolved then there wouldn't be a need for AngularJS.
Or AngularJS would be a lot different from what it is today. Perhaps, yet another MVC framework.
Originally, Angular was designed as a way of enabling designers to use HTML markup to build application without having to know how to program
The originally goal for Angular was to provide a way for designers to use HTML markup to build application without having to know how to program
The core belief is that the best way to build user interfaces is by using declarative programming
In this approach, designers would be able to declare the behavior or components without knowing how the underlying behaviors were implemented
The basic premise is a powerful one: Allow designers to sketch using HTML, then allow developers to build components and behaviors.
Rinse and repeat
The more components and behaviors that developers build the more powerfully, designers can sketch and iterate.
Here's the structure of the basic angular enabled page we'll reuse in this presentation.
<!DOCTYPE html> <html ng-app> <head> <title>Basic Angular App</title> </head> <body> <script src="angular.min.js"></script> <script src="app.js"></script> </body> </html>
Before we dig too deeply into code lets examine a few core concepts...
Here is a basic HTML file that uses angular. We'll use this structure through this presentation. At the top of the file we see an ng-app attribute. This is simply a data tag which tells which part of the DOM to manage.
Within the bottom of the body tag we see that angular is loaded along with our app.js script.
This is all that is required to begin using AngularJS.
Before we dig too deeply into code lets examine a few core concepts and key features.
I promise we'll be back in code shortly.
The goal here is to get a sense of what's available and how we can take advantage of Angular in our own applications.
Angular core developers would be the first to admit that Angular is based heavily on ideas which are far from new.
After all, developers were using existing JavaScript frameworks long before Angular was introduced.
What makes Angular interesting to developers is that it represents an evolution over older frameworks.
One that embraces web standards and modern best practices.
It's all about the markup. Well not actually.
However, Angular treats HTML as a first class citizen rather than an ugly girlfriend.
This focus on HTML is not misplaced as making HTML more useful and ultimately a pleasure to work is an important achievement
Angular makes this possible by embracing declarative programming
Angular embraces HTML, by allowing designers and developers to describe what their HTML should do
We touched on this idea earlier, where Angular was designed to enable designers to "declare" the behaviors associated with their markup.
This declarative approach is different from the imperative approach we developers do when we write Python, Ruby or JavaScript code.
With declarative programs we describe what programs should do and not how they're implemented.
Angular embraces this approach allowing us to do this using directives and HTML behavioral annotations
A core Angular philosophy is that the best way to build UI's is using declarative syntax. With Angular we add behavior to HTML markup using directives.
Let's take a closer look at this directive stuff.
HTML5 adds lots of new elements to HTML:
This helps relieve the pressure of overloading div elements in ways that makes HTML less readable.
The new HTML elements are great. But what if you wanted to create your own elements?
Angular, extends HTML to allow you do just that.
The HTML5 data attribute allows designers to specify additional properties and behaviors for HTML5 elements.
By querying the DOM, programmers can detect the presence of attributes to augment the element.
Coupled with the new HTML5 elements, data attributes contributed to providing considerably more expressive power than was previously available.
This was a really big step forward for HTML
HTML5 data attributes allowed frameworks like jQueryMobile to simplify building mobile applications.
In this example, jQueryMobile uses the data-role and data-filter-placeholder attributes to determine how the list should be transformed
<ul data-role="listview" data-filter="true" data-filter-placeholder="Search fruits..." data-inset="true"> <li><a href="#">Apple</a></li> <li><a href="#">Banana</a></li> <li><a href="#">Cherry</a></li> <li><a href="#">Cranberry</a></li> <li><a href="#">Grape</a></li> <li><a href="#">Orange</a></li> </ul>
From the above to this...
To this:
Beyond the mobile styling of what started off as simple markup, jQueryMobile has added behavior to mimic a popular component that allows for data navigation on mobile devices.
The rows highlight as the user moves up and down the list, and the button on the right cause the panel to side to the left revealing a detail panel.
The search field at the top of the control allows for filtering of the list in realtime.
Angular fully embraces this paradigm by allowing developers to build their own component using directives.
Angular calls these directives
Earlier, we saw examples of directives when we looked at HTML for our basic angular app
<!DOCTYPE html> <html ng-app> <head> <title>Basic Angular App</title> </head> <body> <script src="angular.min.js"></script> <script src="app.js"></script> </body> </html>
The ng-app in the markup is an Angular directives used to inform Angular where the Angular application begins
Source: /samplecode/BasicAngularAppWhen the Angular script loads it scans the DOM looking for the ng-app directive. Angular then restricts its operations to just the scope of the ng-app directive.
You can decorate a single div with the ng-app directive and only use Angular features within that div.
You can even create your own directives. We'll revisit this topic a bit later.
The declarative nature of HTML and the ability to extend it using directives is fundamental to what Angular tries to help designers and developers achieve
Many of Angular's features are designed first and foremost to support this goal and secondarily to provide the tools required to build non-trivial web applications.
One way in which Angular does this is with a concept called data binding.
Angular's ability to extend HTML using a declarative approach is what distinguishes Angular from other JavaScript frameworks.
And if that's all Angular offered it would still be a very useful tool.
However, Angular doesn't stop there. In fact, it goes far beyond that with a suite of tools to address building modern, complex and production ready applications.
Data Binding: This is angular's secret sauce for seamlessly syncing data between models and views.
Scope: The Scope in Angular is a shared context used to store model data. The cool thing about the scope is that it can be shared. Furthermore, expressions in views can access scope data.
Modules are a specialized container for organizing your code. You can add things like controllers, directives, and services.
Controllers: The C in MVC, this is the main place you store your application specific business logic used to power views.
Dependency Injection: Angular features a dependency injection system that allows you to create and register injectable modules which can be made available to other parts of your application.
Providers: Angular implements a concept called a provider which can be used alone, or to build Factories and Services which are dependency injectable.
Support for testing: Angular includes support for both unit testing and End-to-End testing. The tools described above aid in making your applications more testable by supporting separation of concerns.
And there's more. However, with Angular you can use as little or as much as you need.
We'll review each of these features later in this presentation.
Angular support application separation of concerns using MVC and modules such as services and routers
In Angular, the Model is implemented using the Scope
The Scope, as we touched on previously is a context for storing data.
Views are simply HTML templates with declarative annotation and data interpolations. I stress the word "REAL" here because other JavaScript functions handle HTML templates as string rather than real DOM elements. This is one of the features which make using Angular more natural than other frameworks.
And lastly, Controllers. Controllers are just plain old JavaScript objects, created using a contructor function. Angular passes the associated Scope to your contructor function along with any other modules you need via dependency injection.
An important concept here is that while you can use as little or as much of Angular as you need, each feature is designed to work together to help you tackle even the most challenging projects.
Angular supports the ability to bind data to markup and to bi-directionally update that data when the data changes.
Let's take a closer look.
!doctype html> <html ng-app> <head> </head> <body> <div> <label>Name:</label> <input type="text" ng-model="yourName" placeholder="Enter a name here"> <hr> <h1>Hello {{yourName}}!</h1> </div> <script src="js/angular.min.js"></script> </body> </html>
The ng-model in the <input> markup above is an Angular directive used to bind data an input control
In the example above the ng-model directive is used to bind data to an input control.
The double curly braces (aka mustache tags) allow us to use the bound data.
Expressions can be evaluated inside of mustache tags
<!DOCTYPE html> <html ng-app> <head> <title>DataBinding</title> </head> <body> <h2>Live text: {{ data.message }}</h2> <h2>{{ "Hello " + "World!" }}</h2> <h2>{{ 2 + 4}}</h2> <label>Message: </label> <input type="text" ng-model="data.message"> <script src="angular.min.js"></script> </body> </html>Source: /samplecode/DataBinding
You can do a lot more with data binding. Inside of mustache tags you can have expressions evaluated.
Those expressions can use data values you define. It's important to note that this isn't JavaScript, they're expressions which Angular parses and makes sense of.
The beauty of this is that has the data values change the page updates without requiring a round trip to a backend server.
<!DOCTYPE html> <html ng-app> <head> <title>Data binding and Filters</title> </head> <body> <p>1) Cost: {{ 11.99 + (11.99 * 0.33) | currency }}</p> <p>2) Data: {{ 1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z' }}</p> <p>3) Lowercase: {{ "Buy Now!" | lowercase }}</p> <p>4) Uppercase: {{ "Buy Now!" | uppercase }}</p> <p>5) Here is some JSON data: {{ {'Boy':'Fred', 'Girl':'Jill'} | json }}</p> <script src="angular.min.js"></script> </body> </html>Source: /samplecode/DataBindingWithFilters
Introduce filters
currency
capitalization
1) Cost: $15.95
2) Data: 2010-10-29 05:40:23 +0200
3) Lowercase: buy now!
4) Uppercase: BUY NOW!
5) Here is some JSON data: { "Boy": "Fred", "Girl": "Jill" }
<!DOCTYPE html> <html ng-app> <head> <title>DataBindingWithClasses</title> <style> .red { color: red; } .green { color: green; } .blue { color: blue; } </style> </head> <body> <h1 class="{{ data.classColor }}">Basic Angular App</h1> <label>Title color: </label> <input type="text" ng-model="data.classColor"> <script src="angular.min.js"></script> </body> </html>Source: /samplecode/DataBindingWithClasses
There's a lot more we can do with data binding. But we'll need to move on...
Data Binding with Classes
Title color:You may have noticed that our previous examples were missing a few things we've all taken for granted.
Absent from the examples are that there are no HTML class or id's
Also, we haven't written a single line of JavaScript and we didn't have to register any event handlers to support the data binding
What is this magic? We'll see how this works a bit later.
Angular employs a concept called Scope. In many ways Scope is the glue that binds many Angular features.
Scope is an execution context used to hold data, functions and perform tasks such as watching expressions for changes and firing events.
Beginning Angular developers sometimes confuse scope with their data models. Instead scope is a place where a data model can be stored and shared.
<!DOCTYPE html> <html ng-app ng-init="data.message='Hello, from your application scope.';"> <head> <title>Simple Scope</title> </head> <body> <h2>Scope says: {{ data.message }}</h2> <script src="angular.min.js"></script> </body> </html>Source: /samplecode/SimpleScope
A scope is a JavaScript object.
In the last slide we talked about scope being a JavaScript object, however we also learned the scope include helper function to perform various data binding related tasks.
Angular does this by extending plain JS objects with its own scope object. This retains the data and functions you've added to your scope in addition to the one's Angular has added.
Discuss RootScope and Scope
https://github.com/angular/angular.js/wiki/Understanding-Scopes
With Angular we can define our own element as I did below with the my ph-panel directive:
<ph-panel title="This is the panel's title"> <p>This is the panel's body.</p> </ph-panel>
Not only does Angular include a large collection of directives, it also allows developers to build their own custom directives.
In this example we see a ph-panel directive which converts the markup into a styled panel complete with a title and body area.
Notice how we can provide the ph-panel with a title attribute.
Here is the live code using the ph-panel directive:
This is the panel's body.
A few extra lines for good measure
A few extra lines for good measure
A few extra lines for good measure
A few extra lines for good measure
In Angular, the topic of directives is a large one. In fact, Alex Vanston wrote "Angular Directives", an entire book which explore directives
<!DOCTYPE html> <html ng-app="myApp"> <head> <title>Simple Angular Module</title> </head> <body> <script src="angular.min.js"></script> <script src="app.js"></script> </body> </html>
angular.module('myApp', []);Source: /samplecode/SimpleModule
Angular provides Modules as a place to group functionality whereby allowing you to organize your code while abiding by best practices such as not polluting the global namespace
In the first listing above we see that we have now specified a name value to ng-app. This let's angular know that we have an Angular application module called myApp
In our app.js file we simply call the module function on the Angular object passing it the name of our module and an empty array.
The empty array is a placeholder to specify any dependencies our module might have.
An important takeaway here is that there is global angular object which was introduced when we loaded angular on our HTML page using the script element.
When angular loaded it looked for the ng-app data attribute (aka directive) and found that we provided a named application module called myApp.
Lastly, we created a module in our app.js file.
We'll revisit modules a big later.
<!DOCTYPE html> <html ng-app="myApp"> <head> <title>Simple Controller</title> </head> <body > <div ng-controller="myFirstController"> {{data.message}} </div> <script src="angular.min.js"></script> <script src="app.js"></script> </body> </html>
angular.module('myApp', []) .controller('myFirstController', function($scope) { $scope.data = { message: 'Hello from a simple controller!' }; });Source: /samplecode/SimpleModule
Another organizational feature angular provides is controllers.
In controllers we can implement our applications business logic and is the C in Model View Controller paradigm.
We specify controllers in our HTML markup using the Angular ng-controller directive.
In our example here we've added the ng-controller directive to a div element.
This means that the controller named myFirstController will operate on the div element and anything inside of it.
We say that the myFirstController is scoped around or to the div element.
Angular actually creates a new scope for our controller to use.
Notice that we have a data bound expression (there's that curly mustache again) around data.message.
We defined data.message in our controller using the code shown in the second code listing.
There we've simply called the angular object's controller function to define our new controller.
The second parameter to controller is an anonymous function which includes a $scope parameter.
Angular is responsible for invoking our anonymous function and passing a new scope to our controller.
From that point on we're able to attach data and functions to our scope object for use in data binding and other operations.
You see how I've chained the controller call to the result of the module call above.
As you can see, Angular object functions are chainable. But why did I do this?
Using a chrome plugin called Batarang we can see that Angular did indeed create a new scope. Scope 003.
Here we see the data object we created to include our message.
This screen shot also reveals an important point, that scopes can be nested.
Because scopes are essentially JavaScript objects they can be inherited.
If we defined one controller within another, the second one would inherit the values of the first,
but the first would not have access to the inner scope of the nested controller.
var myApp = angular.module('myApp', []); myApp.controller('myFirstController', function($scope) { $scope.data = { message: 'Hello from a simple controller!' }; });
angular.module('myApp', []) .controller('myFirstController', function($scope) { $scope.data = { message: 'Hello from a simple controller!' }; });
After all, I could have just done this instead of chaining.
Chaining is cleaner as it doesn't create a new global variable called myApp which needs to be passed around.
Again, Angular is all about best practices!
<div ng-controller="myFirstController"> <p>FIRST CONTROLLER<br> First controllers message: [ {{data.message}} ]<br> Second controllers message: [ {{data2.message}} ]<br> Third controllers message: [ {{data3.message}} ]</p> <div ng-controller="mySecondController"> <hr> <p>SECOND CONTROLLER<br> First controllers message: [ {{data.message}} ]<br> Second controllers message: [ {{data2.message}} ]<br> Third controllers message: [ {{data3.message}} ]</p> </div> </div> <div ng-controller="myThirdController"> <hr> <p>THIRD CONTROLLER<br> First controllers message: [ {{data.message}} ]<br> Second controllers message: [ {{data2.message}} ]<br> Third controllers message: [ {{data3.message}} ]</p> </div>Source: /samplecode/NestedControllers
Ok, let's get back to our regularly schedule program.
In our earlier examples we saw how controllers get a scope passed into them.
But what happens when controllers are nested? And how does scope visibility come into play?
In this example we define three controllers myFirst, Second and Third Controller
Our second controller is nested inside of our first controller, while the third controller outside of both
Before we discuss how this impacts scope, let's look at how we define our three controllers in JavaScript
angular.module('myApp', []) .controller('myFirstController', function($scope) { $scope.data = { message: 'Hello from the first controller!' }; }) .controller('mySecondController', function($scope) { $scope.data2 = { message: 'Hello from the second controller!' }; }) .controller('myThirdController', function($scope) { $scope.data3 = { message: 'Hello from the third controller!' }; });Source: /samplecode/NestedControllers
So here we chain our three controllers to our Angular application module.
In each controller we add a data item with a custom message.
Notice that there isn't any nesting specified here! This is only definition
Nesting is specified in a declarative manner in our HTML.
Let's use Batarang to examine scope behaviors.
At the top, we see the output from our three controllers
Each tries to display the data.message(x) value from its accessible scope.
The goal is to determine what scope data each controller has access to.
The first controller has access to its own message but can't see the message of it's nested (child) controller, nor the value of the third and sibling controller.
The second controller which is nested inside of the first controller, inherits visibility to it's parent's (outter) controller message and as expected has access to its own message.
The third controller is outside of both the first and second controller and thus only see's its own scope message.
The Angular Batarang plugin shows how the scopes are setup and visually confirms the nesting relationships
The last controller topic we'll examine concerns methods and scopes
We learned that an Angular Controller is a JavaScript constructor function.
So you might expect to use prototypical inheritance to setup member functions.
However that's not really the Angular way.
In Angular, controllers are used to setup the initial state of a scope and to add behaviors to the scope.
This is especially useful as it means that methods can be made accessible to directives and other controllers which might have visibility into the scope.
When you need to create lots of functions to organize your code, you should do so in a provider, service, or factory.
That will help avoid creating monolithic controllers which simply attach lots of functions to a scope.
angular.module('myCoolApp', []);
angular.module('myCoolApp', ['ngRoute']);
angular.module('myCoolApp', ['ngRoute']); .config(function($routeProvider) { 'use strict'; $routeProvider .when('/', { templateUrl: 'views/main.html', controller: 'MainCtrl' }) .otherwise({ redirectTo: '/' }); });
Dependency Injection is a design pattern that describes how a components can receive their dependencies
This prevents needing complex component loaders and methods of resolving circular dependencies.
The gist of this is that a dependency injection system provides methods for registering components and then passes those components where they are required.
A benefit of this is that components don't have to manage locating other components - they're simply available when needed.
Lets have a closer look at this. Earlier we saw how we create our Angular application module using the following code.
The empty array on the right meant that we were not requiring any dependencies for our app.
However, lets say that we wanted to take advantage of Angular's view routing mechanism.
All we need to do is specify ngRoute in our array of dependencies.
Then we'll write code which uses the ngRoute dependency and configure our application's routes.
You can see here that the first parameter to the application config function is $routeProvider.
Angular takes care of ensuring that it passes an ngRoute provider to the anonymous function.
We simply use it without having to load it ourselves.
We'll continue discussing dependency injection in the next section on Angular Providers.
Angular has a concept called providers which is used to implement factories and services.
This allows you to build reusable library-like components with their own function API.
They help promote cleaner and better structured code which is both maintainable and testable.
Much of the functionality that Angular offers comes to us via providers.
We're encouraged to not only leverage the existing providers, but also to create our own.
Part of the power behind Providers is that they automatically link to the dependency injection system making it easy for you to use your providers, services and factories.
<!DOCTYPE html> <html ng-app="myApp"> <head> <title>Simple Service and Factory</title> </head> <body > <div ng-controller="myController"> <p>Get User from Service: {{ userFromService }}</p> <p>Create new user from Factory: {{ createUserWithFactory('Anatoly', 'Karpov') }}</p> <p>Create another new user from Factory: {{ createUserWithFactory('Magnus','Carlsen') }}</p> </div> <script src="angular.min.js"></script> <script src="app.js"></script> </body> </html>Source: /samplecode/SimpleServiceAndFactory
Here is the HTML for our simple service and factory example.
The first paragraph element simply displays the userFromService data item from the current scope.
The second and third paragraphs call two functions defined on the scope.
This is basically what we're already familar with.
angular.module('myApp', []) .controller('myController', ['$scope', 'FirstService', 'FirstFactory', function($scope, myFirstService, myFirstFactory) { $scope.userFromService = myFirstService.getUser(); $scope.createUserWithFactory = function(firstName, lastName) { var user = myFirstFactory.createUser(firstName, lastName); return JSON.stringify(user); }; }]) .service('FirstService', function() { var user = { "firstName": "Garry", "lastName": " Kasparov" }; this.getUser = function() { return JSON.stringify(user); }; }) .factory('FirstFactory', function() { return { createUser: function(firstName, lastName) { return { "firstName": firstName, "lastName": lastName }; } }; });Source: /samplecode/SimpleServiceAndFactory
The JavaScript portion is much more interesting.
Here we define our controller. The big difference here is that we pass FirstService and FirstFactory string into our controller definition.
This is dependency injection at work. Angular looks for providers which we've defined by those names.
Just below our controller we see a service definition. Noticed that it isn't very different from controllers we've created.
Our FirstService returns an object which has a getUser member. Services are essentially singltons which return data which they create or already hav access to.
The object services return is created once and return however many times it's called.
Keep in mind that this doesn't mean services return the same data when its functions are called... only that the object they return is created once.
Factories are different in that Angular creates a new object to return each time. If invoked twice, each object returned will be a new instance.
Get User from Service: {"firstName":"Garry","lastName":" Kasparov"} Create new user from Factory: {"firstName":"Anatoly","lastName":"Karpov"} Create another new user from Factory: {"firstName":"Magnus","lastName":"Carlsen"}
Here's the output from our Service and Factory program.
We discussed that Angular has providers, services and factories
A provider is a module which Angular users to implement services and factories.
When you ask Angular to create a service it essentially uses a provider to create it. The same for when you requested a factory.
So, services and factories are nothing more than syntax sugar (i.e. simpler versions) of providers.
Providers themselves are more powerful in that they can behave differently than a service or factory and can be configured before they're made available.
Let's take a look at creating and configuring our own provider.
<!DOCTYPE html> <html ng-app="myApp"> <head> <title>Provider</title> </head> <body > <div ng-controller="myController"> <p>Get start Date: {{ startDate }}</p> </div> <script src="angular.min.js"></script> <script src="app.js"></script> </body> </html>Source: /samplecode/Provider
The HTML itself isn't special. Let's look at the app.js file.
angular.module('myApp', []) // controller .controller('myController', ['$scope', 'StartDate', function($scope, myDateProvider) { $scope.startDate = myDateProvider.getStartDate(); }]) // provider .provider('StartDate', function() { this.startDate = new Date(); this.$get = function() { var startDate = this.startDate; return { getStartDate: function() { return startDate; } }; }; this.setStartDate = function(newDate) { this.startDate = newDate; }; }) // config .config(function(StartDateProvider) { //StartDateProvider.setStartDate(new Date("October 13, 1975 11:13:00")); });Source: /samplecode/Provider
Ok, so we start with our controller. Notice that we're passing a string named StartDate
That's the name of our provider.
Within our controller we assign the value of calling the start date provider's getStartDate member to the startDate data item on the current scope
Next we define our StartDate provider
Now this is different from how services and factories are setup. We assign an anonymous function to a $get object member.
Like a factory the code assigns a function which returns a function. This allows for data members which are not visible outside this clousure.
When a provider is injected into a controller Angular actually returns the $get function directly.
Services make good managers. Use them when you have data or functionality where a single instance of it will surfice accross your application.
A good example is login (signin) service. Another is a user profile management service.
Factories, when you need instances of objects. Think: birds for your angry birds clone.
Providers, when you need need control then a service or factory can provide or when you need control over how it's created and configured.
So this:
<input class="ipt" type="text" placeholder="name" require ng-model="user.name">
Rather than this:
<input require class="ipt" ng-model="user.name" placeholder="name">
Let's look at a few angular best practices. Visit online style guides for more suggestions, and adapt a style that meets your project's needs.
Angular offers lots of ways to organize your code, using directives, controllers, providers, filters, views, and models.
Under your project's root folder make sure to create folders for each of the above.
That is, organize your code into folders to hold your directives, controllers etc..
Another approach for code organization is to organize by application features. So all of the components relating to user profiles might be stored in the same folder.
Whatever you do, make sure your project is locally organized and maintainable.
Keep your markup clean. Add Angular specific directives at the end of elements.
As we prepare to explore Angular code keep in mind that Angular prefixes its directives with the an NG prefix.
People often ask why the ng prefix? The reason is because NG sounds more like Angular than AN or AG.
Also, and this is somewhat unfortunate for jQuery developers, Angular prefixes many of its services with a dollar symbol.
If I had to guess, and this may be a real strength... the $ symbol could stand for the S in service.
It should go without saying that you shouldn't use these in your own code.
You may have noticed a pattern in the above naming conventions.
Anything that involves a constructor has an uppercase letter prefix.
$timeout instead of setTimeout $interval instead of setInterval $window instead of window $document instead of document $http instead of $.ajax
We can use Karma to test our Angular code
To use Karma in your own app follow the instructions on the Karma GitHub repo.
However, if you're running the tests included with this presentation then Karma will be installed when you run npm install.
Karma executes Jasmine BDD style tests and works with other testing frameworks like Mocha and QUnit.
For end-to-end tests Angular has a tool called Protractor
describe('Simple Test Spec', function() { it('should just pass', function() { expect(true).toBe(true); }); });
A Jasmine test suite is called a Spec.
So, all of our tests will end in *Spec.js
This isn't absolutely necessary, but it's the default Karma setup for Jasmin.
Jasmine test consist of a describe block which
A Jasmine test is just a JavaScript file which calls functions in the Jasmine Testing Framework
A test file consist of three main blocks.
The describe block describes a test suite. Notice that it simply has two parameters. A text label and an anonymous function.
The describe block also encases one or more "it" sections.
An "it" block defines a behavior - that is what should behavior should the test exhibit
Inside of an "it" block you'll add one or more expecations. That is what assertions should the behavior exhibit?
~/AngularPresentation$ ./karma_start.sh INFO [karma]: Karma v0.12.16 server started at http://localhost:9876/ INFO [launcher]: Starting browser Chrome INFO [Chrome 35.0.1916 (Mac OS X 10.9.3)]: Connected on socket Q47fUfs2QdHA5DNhAjXi with id 33541008 Chrome 35.0.1916 (Mac OS X 10.9.3): Executed 1 of 1 SUCCESS (0.01 secs / 0.008 secs)
First make sure you've run npm install on this project's root folder
That will ensure that both Grunt and Karma are installed
At the terminal prompt just run: ./karma_start.sh
You should see output similar to the session shown here.
describe('Simple Test Spec', function() { it('should just pass', function() { expect(true).toBe(false); }); });
INFO [watcher]: Changed file "/Users/cjus/dev/cjus/AngularPresentation/samplecode/SimpleTest/simpleTestSpec.js". Chrome 35.0.1916 (Mac OS X 10.9.3) Simple Test Spec should just pass FAILED Expected true to be false. Error: Expected true to be false. at null.<anonymous> (/Users/cjus/dev/cjus/AngularPresentation/samplecode/SimpleTest/simpleTestSpec.js:3:18) Chrome 35.0.1916 (Mac OS X 10.9.3): Executed 2 of 2 (1 FAILED) (0.032 secs / 0.028 secs) </anonymous>
Normally in Test Drive Development we start with tests that fail
so let's let break our current test
To do this let's change our test expectation toBe false
The
One of the great benifits of Angular's Dependency Injection system is that it make testing your application possible.
The reason is that we can can inject our modules into our Jasmine tests with very little work.
Let see how this works.
describe('Angular element and expression test', function() { var element , $scope; beforeEach(module("myApp")); beforeEach(inject(function($compile, $rootScope) { $scope = $rootScope; element = angular.element("<div>{{2 + 2}}</div>"); element = $compile(element)($rootScope); $scope.$digest(); })); it('should equal 4', function() { expect(element.html()).toBe("4"); }); });
Testing Angular involves introducing a few extra steps into our Jasmine files
In this particular test we're testing an angular expression within an element.
As we learned earlier, Angular expression and directives use the scope for data binding.
So in our test we need to inject the $rootScope, we also need to use the $compile provider to actually compile the expression.
For the most part, this sort of thing happens behind the scenes in Angular apps but we need to do it here because we're working in an isolated test context.
And finally, we need to run the $digest() member on the $scope object. This is something we haven't seen in this presentation but essentially, it runs Angular's internal digest cycle where it updates bindings.
Notice that all of that is wrapped in an inject block and beforeEach. The inject handles the dependency injection, in this case for the $compile and $rootScope providers.
The beforeEach ensures that this block is executed before each "it" behavioral test.
describe('Angular controller test', function() { var myController , scope; beforeEach(module("myApp")); beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); myController = $controller('myController', { $scope: scope }); })); it('should have a getDate function which returns a date', function() { expect(scope.getDate()).not.toBeNull(); }); });Source: samplecode/ControllerTest
Here we have a spec for testing a controller which returns a date.
Here again we ensure that our myApp is available.
Next we inject the $controller and $rootScope providers in order to create a new scope for our controller
We create our controller using the $controller provider and assign our newly created scope.
Now we're ready to test that calling the getDate() member of the scope does indeed return something.
An important point to consider when testing controllers is that we're not really testing the controller but rather the changes it made to its scope.
describe('Angular service test', function() { var Base64Service; beforeEach(module("myApp")); beforeEach(inject(function(_Base64Service_) { Base64Service = _Base64Service_; })); it('should correctly encode a known message', function() { expect(Base64Service.encode('Hello from a simple controller!')).toBe('SGVsbG8lMjBmcm9tJTIwYSUyMHNpbXBsZSUyMGNvbnRyb2xsZXIlMjE='); }); });Source: samplecode/ServiceTest
Testing services is straightforward.
We simply inject our service an test its members.
Google members have written a number of excellent tools which support AngularJS development
TODO: Angular life cycle
AngularJS was created in 2008 and 2009 by Miško Hevery and Adam Abrons
The two set out to build an online JSON storage service which they hosted under GetAngular.com
The value proposition was to simplify building online applications with pay as you go data storage.
They eventually decided to scrap the business venture, but Angular continued to evolve and was eventually open sourced.
Adam left the project, but Misko pressed on while working at Google
At Google, Misko meet Brad Green who recruited him to work on the Google Feedback project
The project was difficult to work with and at one point Misko claimed he could rewrite the product in two weeks using his personal side project, called Angular
At the time Google Feedback had 17,000 pnes of code developed over six months by three developers
Brad took Misko up on this offer and Misko didn't quite pull it off.
Instead it took him three weeks to rewrite the product and reduce the codebase from 17,000 lines to just 1500 line of code
Based on this success, Brad recommended open sourcing the early Angular and recruiting other Googlers to join the project
Because the project was open sourced, developers outside of google took notice of the project and started using and contributing to it
One such person turned out to be another Googler, Marc Jacobs from the Google DoubleClick team
Marc was part of the Google acquisition of DoubleClick and was tasked to convert a DoubleClick app from Microsoft .NET to the Google Platform
Marc, impressed by Angular, devoted a two week sprint to trying the conversion using two parallel approaches: 1) Using AngularJS 2) Using Google's GWT
Two days into the sprint he completed the project using Angular. Then he tried the same project using GWT and after five days he gave up on it.
2013, the Angular team hosted an internal conference at Google offices
Initially, 50 people were expected to attend
197 attendees showed up
In October of 2013, the Angular team hosted an internal conference at Google in Mountain View, CA
They expected around 50 people would attend
When the conference started there were 197 attendees, presenting 101 project within Google
Angular was gaining traction inside and outside of Google
The Angular team started tracking how often developers searched for angular relative to other popular frameworks
The team announced that by mid-2013 the popularity of Angular skyrocketed in comparison to other frameworks
At the 2014, first ever AngularJS conference, Brad and Misko announced that by mid-2013 the popularity of Angular skyrocketed in comparison to other frameworks
Named after the HTML angled bracket
People often ask why the name Angular? AngularJS focuses on HTML markup which contains angled brackets
So Angular was named after the HTML angled brackets
The logo was chosen because the shield resembles the HTML5 logo which also uses a shield and Angular runs on top of HTML5
Also Misko liked the logo because the shield represents Angular shielding developers from the low-level differences among web browsers
You might think all of Angular's features result in a large and bloated framework