Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome, Safari or Firefox browser.

OR

Goal: Learn new framework

  1. Follow the tutorial
  2. Read the documentation
  3. Start coding!
  4. When in doubt use your intuition

Let's talk about Angular

Concepts & components

To learn AngularJS you need to understand the following concepts (In no particular order):

  • MVC
  • Data Binding
  • Dependancy Injection
  • Controllers
  • Directives
  • Services
  • Filters
  • Transclusion
  • Widgets
  • Templates
  • Providers
  • Injector
  • Two-way Data Binding
  • REST
  • Scope isolation
  • Angular Expressions vs. JS
  • E2E & Unit testing
  • Testacular
  • Karma Test Runner
  • The Angular Way

Documentation

The advantage of transclusion is that the linking function receives a transclusion function which is pre-bound to the correct scope. In a typical setup the widget creates an isolate scope, but the transclusion is not a child, but a sibling of the isolate scope. This makes it possible for the widget to have private state, and the transclusion to be bound to the parent (pre-isolate) scope.

Huh?

And documentation...

But... it's not all that bad

Let's change perspective

Let's talk about the Angular Way

Dependency Injection

function MyController($scope) {
	var backend = new httpBackend();
	$scope.articles = backend.article.query({author="Tom"});
}
		
function MyController($scope) {
	var backend = window.project['httpBackend'];
	$scope.articles = backend.article.query({author="Tom"});
}
		
function MyController($scope, $httpBackend) {
	$scope.articles = $httpBackend.article.query({author="Tom"});
}
		

Testability

var httpBackend, myController, mockedData, scope;
mockedData = [ ... ]; // fixture containing test data
mocks.inject(function(_$httpBackend_, $rootScope, $controller) {
	httpBackend = _$httpBackend_; // this is MOCKED version of $httpBackend;
	// which means it can do trickes, e.g.
	httpBackend.whenGET('/api/articles?author=tom').respond(mockedData);
	// new, empty scope for controller we want to test
	scope = $rootScope.$new();
	// instantiate controller using Angular Way
	myController = $controller('MyController', {
               "scope": scope
	});
	$httpBackend.flush();
	expect(scope.articles.length).toBeGreaterThan(0);
}
		

e2e tests

it('should allow creating articles', function() {
	browser().navigateTo('/articles');
	expect(element('h1:contains("Articles")+table>tr').count()).toBe(0);
 	element('button:contains("New Article")').click();
 	expect(element('body').attr("class")).toMatch('modal-open');
 	expect(element('h3:contains("New Entry")').count()).toBe(1);
 	input('article.title').enter('Awesome Article!');
 	select('article.author').option('Tom');
 	select('article.category').option('News');
 	element('button:contains("Save Article")').click();
 	sleep(1); // Allow 1 second for real backend communication
 	expect(
 		        element('h1:contains("Articles")+table>tr').count())
 	.toBeGreaterThan(0);
 });
		

Events

<div ng-controller="MyController">
	<p>My name is { {name} }</p>
	<button class="dark-side-button">>Come to the Dark Side!</button>
</div>
function MyController($scope) {
	$scope.name = "Anakin Skywalker";
	$('.dark-side-button').click(function(e) {
		$scope.name = "Darth Vader";
		alert("don't use alerts for debugging");
	});
}

My name is {{name}}

<div ng-controller="MyController">
	<p>My name is { {name} }</p>
	<button ng-click="darkSide($event)">Come to the Dark Side!</button>
</div>
function MyController($scope) {
	$scope.name = "Anakin Skywalker";
	$scope.darkSide = function(e) {
		$scope.name = "Darth Vader";
		alert("don't use alerts for debugging");
	}
}

My name is {{name}}

Or you could use $scope.$apply()

Can of Worms

Data binding (and DOM manipulation)

		
<div ng-controller="MyController">
	<p class="greeting"></p>
	<button ng-click="darkSide($event)">Come to the Dark Side!</button>
</div>
function MyController($scope, $httpBackend) {
	var compiled, greeting;
	$scope.name = "Yoda";
	compiled = _.template("hello: <%= name %>");
	greeting = compiled({name : $scope.name });
	$('.greeting').append(greeting);
	$scope.darkSide = function(e) {
		$scope.name = "Dark Yoda?";
	}
}

Two-way binding

<div ng-controller="MyController">
	<p >{ {name} }</p>
	<input type="text" ng-model="name" />
</div>
function MyController($scope, $httpBackend) {
	$scope.name = "Yoda";
}

hello: {{name}}

Directives

<div>
	<div ng-controller="Ctrl3">
	<div class="zippy" zippy-title="Details: { { title } }...">{ {text} }</div>
	</div>
</div>
Title:
Text:
{{text}}

And much more...

So is it worth the hassle?

Yes, if...

No, if...

In the end it's a tool

Use the one right for the job

Questions?