120
AngularJS Deep Dive 13 September 2014 Troy Miles

Advanced AngularJS

Embed Size (px)

DESCRIPTION

Slides for the one day Advanced AngularJS class.

Citation preview

Page 1: Advanced AngularJS

AngularJS Deep Dive13 September 2014 Troy Miles

Page 2: Advanced AngularJS

Troy Miles

Over 30 years of programming experience

Blog: http://therockncoder.blogspot.com/

Twitter: @therockncoder

Email: [email protected]

GitHub: https://github.com/Rockncoder

Page 3: Advanced AngularJS

AgendaHow AngularJS works

$scope

Routing

Filters

Unit testing

Directives

Providers & services

$http

$q

Directives Deep Dive

Summary

Page 4: Advanced AngularJS

What We Won’t Cover

Modern JavaScript Programming

Design Patterns

Other Frameworks

Page 5: Advanced AngularJS

How AngularJS Works

Page 6: Advanced AngularJS

AngularJSCreated by Miško Hevery and Adam Abrons in 2009

JavaScript MVC

106 kb production version (minimized, not gzipped)

Declarative programming for UI

Imperative programming for business logic

Page 7: Advanced AngularJS

AngularJS <!DOCTYPE html><html ng-app="moduleName"> <head lang="en"> <meta charset="UTF-8"> <title>NG-Skeleton</title></head> <body><div ng-controller="aController"> </div><div ng-controller="anotherController"> </div><!-- if using jQuery it goes here --> <script src="../libs/angular.min.js"></script><!-- other libs and script files --> </body> </html>

Page 8: Advanced AngularJS

ng-app

Declares the boundary of an Angular app

The first ng-app found will be auto-bootstrapped

ng-app can optionally name a module

Can encompass the entire page <html ng-app>

Or only part of it, <div ng-app>

Page 9: Advanced AngularJS

What the Browser Does?

Loads the HTML

Parses it into a Document Object Model or DOM

The angular.js script is loaded and parse

Angular waits for the DOMContentLoaded event

AngularJS’ bootstrap code executed

Page 10: Advanced AngularJS

DOMContentLoaded vs load event

The load event fires once everything has loaded

The DOMContentLoaded event fires once the DOM has been created

DOMContentLoaded doesn’t wait for CSS, images, or iFrames to load

DOMContentLoaded fires well before load

Page 11: Advanced AngularJS

AngularJS’ Bootstrap

Bootstrap looks for the ng-app directive

There can only be one of these

The module specification is optional

The module specification tells the $injector service which defined module to load

Page 12: Advanced AngularJS

The $injector serviceCreates $rootscope

The mother of all scopes

Linked to the DOM

Creates the $compile service (like a shepherd)

Walks the DOM looking for directives

How ng sees directives no matter how defined

Page 13: Advanced AngularJS

AngularJS Key FeaturesModel View Controller (MVC)

Data Binding

HTML Templates

Dependency Injection

Deep Linking

Directives

Page 14: Advanced AngularJS

Model View Controller

Uses MVC or MVVM or MV* depends on who you ask

The goal is clear separation of concerns

The model is only concerned with data

The view presents the data to the user

The controller applies the business logic

Page 15: Advanced AngularJS

Data Binding

In Angular, binding is built into the framework

Replaces text content of HTML element with the value of the expression

{{ expression }}

<ANY ng-bind=“expression”>…</ANY>

<ANY class=“ng-bind: expression;”>…</ANY>

Page 16: Advanced AngularJS

HTML Templates

Many JavaScript MVC Frameworks use a client-side templating engine

AngularJS doesn’t

Angular uses HTML as its templating engine

No extra markup, no extra libraries

Page 17: Advanced AngularJS

Dependency InjectionA software design pattern that implements inversion of control and allows a program design to follow the dependency inversion principle

Allows a dependency to be passed to an object

Allows code to clearly state dependencies

Leads to code which is easier to debug and test

Makes it possible to minimize apps without breaking them

Page 18: Advanced AngularJS

Dependency InjectionThe DI pattern in AngularJS looks funky due to JavaScript’s shortcomings

The pattern is name of module, dot, name of provider, name of object, an array with the list of dependencies in strings and a function as the last item in the array

tempApp.controller('CurrentCtrl', ['$scope', function ($scope) { $scope.temp = 17; }]);

Page 19: Advanced AngularJS

Deep Linking

Deep Linking enables a website to restore state from a URL

URL and bookmarks are key part of the web

Early Single Page Apps lacked deep linking

They broke SEO and user expectation

Page 20: Advanced AngularJS

Directives

“The coolest feature of AngularJS” - Misko Hervey

Attach behavior to DOM elements

Can nearly turn HTML into a DSL

Page 21: Advanced AngularJS

$scope

Page 22: Advanced AngularJS

InheritanceClassical Inheritance

Most object oriented languages use classes as their inheritance mechanism

Prototypical Inheritance

Objects inherit from other objects, no need for classes

Demo child inheriting from parent

Once a property is added, everyone on the inheritance chain gets it, regardless of when created

Page 23: Advanced AngularJS

Scope Inheritance

Scopes can be nested to limit access to app properties

Provides access to shared model properties

Nested scopes are either "child scopes" or "isolate scopes"

Child scope inherits prototypically

An isolate scope does not

Page 24: Advanced AngularJS

Plain Old JavaScript ObjectsAngular uses dirty checking to keep the model and view in sync

Dirty checking runs equality checks over the data the view depends, it is a brute force method

Watch expressions are run every time data could change

Watch expression should be fast and idempotent

Page 25: Advanced AngularJS

$watch()

Watches for model mutations

$watch(watched expression/function, handler, …)

Watch expression must be fast and idempotent

Page 26: Advanced AngularJS

$apply()

Called when you are transitioning from non-angular world into angular world

calls $digest

Page 27: Advanced AngularJS

$digest()

A digest is just plain old dirty checking

It works on all browsers and is totally predictable

Page 28: Advanced AngularJS

Digest Loop

Possibility of an endless loop

Will only go 10 deep before exception is thrown

NOT like a game loop

Page 29: Advanced AngularJS

$parse()

Evaluates expressions, safely

Bridges gap between the DOM and AngularJS

Used by AngularJS to interpolate values

Page 30: Advanced AngularJS

Module

A collection of configuration and run blocks which get applied to the app during bootstrap

Most apps will have one module

Most 3rd party libraries will come with their own

You inject dependent modules into yours

Page 31: Advanced AngularJS

Configuration Blocks

Get executed during the provider registration and configuration phase

Only providers and constants can be injected into configuration blocks

Shortcut methods available for some common configuration blocks

Page 32: Advanced AngularJS

Configuration Shortcuts

value(‘constantName’, 123)

factory(‘factoryName’, function(){return 123;})

directive(‘directiveName’, …)

filter(‘filterName’, …)

Page 33: Advanced AngularJS

Run Blocks

Closest thing Angular has to a main method

Executed after services have been configured

Typically contains code which is hard to unit test

Page 34: Advanced AngularJS

Order of Execution

Configuration blocks

Run blocks

Directive compile functions

Controllers

Directive link functions

Page 35: Advanced AngularJS

$timeout

guaranteed to fire after current digest loop

If you use a setTimeOut, you will also need to do $apply

$timeout does this for you

Page 36: Advanced AngularJS

Lab - $scope

Page 37: Advanced AngularJS

Filters

Page 38: Advanced AngularJS

Understanding FiltersUsed to format data displayed to user

Strictly front-end, doesn’t change model data

Accessible using declarative or imperative syntax

{{ expression [| filter_name[:parameter_value] ... ] }}

$scope.originalText = 'hello';$scope.filteredText = $filter('uppercase')($scope.originalText);

Page 39: Advanced AngularJS

A tour of built-in filterscurrency

date

json

lowercase

uppercase

number

filter

limitTo

orderBy

Page 40: Advanced AngularJS

Lab - Using Filters

Page 41: Advanced AngularJS

Using Filters in Controllers

The filter must be injected into the controller

Use the mangled name, <filterName>Filter

Filters can also be used with services and directives

Page 42: Advanced AngularJS

Building custom filterstempApp.filter('minimum', [function () { return function (arrTemp, minimum) { var filteredArray = []; var min = minimum ? minimum : 15; angular.forEach(arrTemp, function (value, key) { if (value.temp >= min) filteredArray.push(value); }); return filteredArray; }; }]);

Page 43: Advanced AngularJS

Lab - Custom Filters

Page 44: Advanced AngularJS

Unit Testing

Page 45: Advanced AngularJS

Jasmine

The default unit tester for angularjs

Others will also work

Behavior driven approach

Page 46: Advanced AngularJS

Describe - test suite

Describe is a global jasmine function

Two params

string - name of the test suite

function - implementation of the suite

Can be nested

Page 47: Advanced AngularJS

it - specs

it is a global jasmine function

Looks like describe

A spec contains one or more expections

If all expectations true, it is a passing spec

If any expectation fails, it is a failing spec

Page 48: Advanced AngularJS

Expectations

Expect function

One param

The actual

Chained to a Matcher function

Page 49: Advanced AngularJS

Matchers

Take the output of the expect function and compare it to something

Implement a boolean compare between actual value and expected

Reports to Jasmine if the expectation is true or false

Any matcher can be negated with a not before it

Page 50: Advanced AngularJS

Some matchers

toBe - compares using ===

toEqual - works for literal variables and objects

toMatch - for regular expressions

toBeDefined - compares against 'undefined'

toBeUndefined - also compares against ‘undefined'

Page 51: Advanced AngularJS

Some matchers (CONTINUE)

toBeNull - compares against null

toBeTruthy - truthy boolean casting

toBeFalsy - falsy boolean casting

toContain - finds an item in array

Page 52: Advanced AngularJS

Some matchers (CONTINUE)

toBeLessThan

toBeGreaterThan

toBeCloseTo - precision math comparison

toThrow - should throw an exception

Page 53: Advanced AngularJS

beforeEach / afterEachAre setup and teardown functions

called before and after each spec it

this

beforeEach, it, and afterEach share the same this

it is cleared before call spec call

any beforeEach not included in a describe block is executed before any Jasmine test

can use this to add custom matchers

Page 54: Advanced AngularJS

Disabling suites and specs

prepend an 'x' before describe or it

specs inside a disabled suite are not ran

Page 55: Advanced AngularJS

Lab - Unit Testing

Page 56: Advanced AngularJS

Directives

Page 57: Advanced AngularJS

Directives

Introduction to Directives

jQuery integration

Using a jQuery UI Widget

Page 58: Advanced AngularJS

Directives

Markers on a DOM element that attach a behavior to it

Can be an attribute, element name, comment, or CSS

The HTML compiler traverses the DOM at bootstrap and matches directives to DOM elements

Page 59: Advanced AngularJS

Directives Names<div timePicker></div>

<div time-picker></div>

<div time:picker></div>

<div time_picker></div>

<div x-time-picker></div>

<div data-time-picker></div>

Page 60: Advanced AngularJS

Directive Location

Tag name: <timePicker></timePicker>

Attribute: <div data-rnc-time-picker></div>

Class: <div class=“time-picker;”></div>

Comment: <!— directive:time-picker —>

Page 61: Advanced AngularJS

Built-in Directives

ng-app

ng-bind

ng-controller

ng-href

ng-readonly

ng-repeat

ng-src

ng-submit

ng-transclude

ng-view

Page 62: Advanced AngularJS

jQuery Integration

AngularJS includes a mini version of jQuery called jqLite

It is perfectly compatible with the full version of jQuery

jQuery must be loaded before Angular or it won’t see it

Page 63: Advanced AngularJS

Using a jQuery Widgetapp.directive('timePicker', function () { var today = new Date(new Date().toDateString()); return { require: '?ngModel', link: function ($scope, $element, $attrs, ngModel) { var initialized = false; ngModel = ngModel || { "$setViewValue": angular.noop }; // where is the missing time value? setTimeout(function () { initialized = $element.timepicker() .on('changeTime', function (ev, ui) { var sec = $element.timepicker('getSecondsFromMidnight'); ngModel.$setViewValue(sec * 1000); console.log("sec = " + sec); }); }); ngModel.$render = function (val) { if (!initialized) { //If $render gets called before our timepicker plugin is ready, just return return; } $element.timepicker('setTime', new Date(today.getTime() + val)); } } }});

Page 64: Advanced AngularJS

Lab - jQuery UI Widget

Page 65: Advanced AngularJS

ng-bind vs ng-modelng-bind is one way data binding, aka output

ng-bind renders a property on scope

ng-bind has a shortcut, {{expression}}

ng-bind is preferred over shortcut

ng-model is for two-way data binding

ng-model is intended for form elements

Page 66: Advanced AngularJS

Providers

What are providers?

Types of providers

Services

Factories

Providers

Page 67: Advanced AngularJS

What are providers?

Objects that are instantiated and wired together automatically by the injector service

The injector creates two kinds of objects:

services - defined by the developer

specialized objects - Angular framework pieces, controllers, directives, filters, or animations

Page 68: Advanced AngularJS

Types of providersConstants

Value

Decorator

Provider

Service

Factory

Page 69: Advanced AngularJS

Services

Substitutable objects that are wired together using DI

Used to organize and share code across app

Only instantiated when an app component depends on it

Singletons

Built-in services always start with “$”

Page 70: Advanced AngularJS

Factories

Introduction to shared components

Dependency injection deep dive

Building custom factories & services

Persisting data to a Web API service

Page 71: Advanced AngularJS

Routing

Page 72: Advanced AngularJS

Server-side Routing vs Client-side Routing

Traditionally changing the URL triggers server side request

Angular watches $location.url() and tries to map it to a route definition

Page 73: Advanced AngularJS

ngRoute

Provides routing and deep linking services and directives

Must include angular-route.js in HTML, after angular.js

Must mark ngRoute as a dependent module

Use ng-view indicate where partials will be displayed

Page 74: Advanced AngularJS

Pushstate URLs vs hash based URLs

By default Angular uses hash “#” based URLs

It can use HTML5 push state, with fallback

$locationProvider.html5Mode(true);

Page 75: Advanced AngularJS

Lab - Routing

Page 76: Advanced AngularJS

$http

Page 77: Advanced AngularJS

$http

Facilitates communication with a remote HTTP service via the XMLHttpRequest object or JSONP

Based on deferred/promise API

Requires two parameters:

method - the HTTP method to call

url - the location of the HTTP service

Page 78: Advanced AngularJS

JSON Test

A free service for testing JSON based application

http://www.jsontest.com

Echo JSON returns a customized JSON object

Page 79: Advanced AngularJS

Lab - $http

Page 80: Advanced AngularJS

Directives Deep Dive

Page 81: Advanced AngularJS

jQuery vs Directive<body> <div id="myElement" my-directive></div> </body> $(document).ready(function(){ $('#myElement').myPlugin({pluginOptions: options}); });

Page 82: Advanced AngularJS

Directives are …

The heart of AngularJS

Declarative

Data driven

Conversational

Page 83: Advanced AngularJS

.directive

Is a shortcut to the same method on compiler provider

Same pattern used in controllers, services, and filters

Not actually a a directive definition but a factory

Page 84: Advanced AngularJS

Parameters

$scope - the scope for this instance of the directive

$element - the jQuery wrapped element

$attrs - any attributes attached to the element

Page 85: Advanced AngularJS

Return value

a configuration object

a function

Page 86: Advanced AngularJS

Returns a functionangular.module('myApp.directives', []) // this is a factory method which actually creates .directive('myAwesomeDirective', ['api', function () { // one time initializations return function ($scope, $element, $attrs) { // directive work goes here }; }]);

Page 87: Advanced AngularJS

Returns an objectangular.module('myApp.directives', []) // this is a factory method which actually creates .directive('myAwesomeDirective', ['api', function (api) { // one time initializations // return a configuration object return { restrict: ‘A’, priority: 10, terminal: false, template: '<div<h3>{{title}}</h3></div>', templateUrl: 'myDirective.html', replace: true, compile: function (element, attributes, transclude) {}, link: function($scope, $element, $attrs){}, scope: true, controller: function($scope, $element, $attrs){}, require: 'ngModel', transclude: true }; }]);

Page 88: Advanced AngularJS

Configuration objectrestrict

priority

terminal

template/templateUrl

replace

compile

link

scope

controller

require

transclude

Page 89: Advanced AngularJS

restrictDefines use of directive

Styles (EACM)

E - element

A - attribute, the most common

C - Class - RARELY USED

M - Comment - RARELY USED

Page 90: Advanced AngularJS

E - element

Very semantically accurate

Looks cool

Internet Explorer issue

will read in as div

to fix, in headdocument.createElement(‘my directive')

Page 91: Advanced AngularJS

A - attribute

The default if restrict not defined

Protects from IE troubles

Provides some semantic meaning

Best practice

Page 92: Advanced AngularJS

priority

Specifies in what order the directives should be executed

There may be multiple directives on the same node

default is 0

Page 93: Advanced AngularJS

terminal

Related to priority

terminal dictates whether or not directive execution should stop after the priority level

default is false

Page 94: Advanced AngularJS

template/templateUrl

Both template properties function mostly the same

For templateUrl, compile/link process will be suspended until the template is loaded

Can contain other directives nested within them

Page 95: Advanced AngularJS

replace

Whether the whole element should be replaced with the template, or just the element's inner HTML

If replace - must have only one root node

default is false

Page 96: Advanced AngularJS

compile/link

compile - tasks requiring restructuring of the DOM

link - attaches scope to the compiled element

Could replace the configuration object with a link function

Page 97: Advanced AngularJS

scope

default - null - same scope as attached object

true - new scope plus inherits from parents (prototypal inheritance)

{} - isolate scope object

Page 98: Advanced AngularJS

controller

can store many of the properties or methods that you might normally attach to scope

if attached to the controller itself, they can be shared with other directives

Page 99: Advanced AngularJS

requireTells Angular to grab the instance of one directive's controller and make it available to another directive

?ngModel, means that requirement is optional

^ngModel, traverse up from the element node through the DOM tree <div ng-model="data.property"> <input autocomplete-input /> </div>

Page 100: Advanced AngularJS

transclude

provides ability to have isolate scope

but still have access to parent scope's properties

Page 101: Advanced AngularJS

jQuery UI Widget Walk-thru

Page 102: Advanced AngularJS

Project Organization

Recommend seeding with Yeoman

Yeoman will create the app scaffolding

It also includes both Jasmine for unit tests

And Karma as a test runner

Getting Yeoman running on Windows is slightly challenging

Page 103: Advanced AngularJS

Yeoman

Scaffolding for modern web apps

Yeoman is a node package module, so node is required

It is free and open source

http://yeoman.io/

Page 104: Advanced AngularJS

Promises / $q

Page 105: Advanced AngularJS

Why promises?$.get('api/gizmo/42', function(gizmo) { console.log(gizmo); // or whatever});

Page 106: Advanced AngularJS

But quick can turn into…$.get('api/gizmo/42', function(gizmo) { $.get('api/foobars/' + gizmo, function(foobar) { $.get('api/barbaz/' + foobar, function(bazbar) { doSomethingWith(gizmo, foobar, bazbar); }, errorCallback); }, errorCallback); }, errorCallback);

Page 107: Advanced AngularJS

What is a promise?

A promise is an object that represents the return value or the thrown exception that the function may eventually provide

A promise can also be used as a proxy for a remote object to overcome latency

Resolution of a promise is always asynchronous

Page 108: Advanced AngularJS

What is $q?

Inspired by the Kris Kowal's Q library

Q has more features than $q

Q is also bigger

$q is bound to the $rootScope for faster propagation

Page 109: Advanced AngularJS

The promise pattern

A promise has two components

Deferreds - represents a unit of work

Promises - represents data for the Deferreds

Page 110: Advanced AngularJS

The deferred API

resolve()

reject()

notify()

Page 111: Advanced AngularJS

The promise API

then

catch

finally

Page 112: Advanced AngularJS

Lab - $q

Page 113: Advanced AngularJS

Best PracticesKeep watch expression fast and idempotent

Write unit tests

Keep your code organized

Keep controllers simple

Business logic belongs to models, not controllers

No DOM code in controllers, use directives

Page 114: Advanced AngularJS

SummaryHow AngularJS works

$scope

Routing

Filters

Unit testing

Directives

Providers & services

$http

$q

Directives Deep Dive

Summary

Page 115: Advanced AngularJS

BooksGreen, Brad & Seshadri, Shyam

AngularJS

O'Reilly Media

2013

Vanston, Alex

AngularJS Directives

Packt Publishing

2013

Page 116: Advanced AngularJS

Books…Ford, Brian & Ruebbelke, Lukas

AngularJS in Action

Manning Publications

2014

Knol, Alex

Dependency Injection with AngularJS

Packt Publishing

2013

Page 117: Advanced AngularJS

Books…Hahn, Evan

JavaScript Testing with Jasmine

O'Reilly

2013

Kozlowski, Pawel & Darwin, Peter Bacon

Mastering Web Application Development with AngularJS

Packt Publishing

2013

Page 118: Advanced AngularJS

Angular Linkshttps://angularjs.org/

https://github.com/angular-ui

http://www.alexrothenberg.com/2013/02/11/the-magic-behind-angularjs-dependency-injection.html

http://arthur.gonigberg.com/2013/06/29/angularjs-role-based-auth/

http://blog.xebia.com/2013/09/01/differences-between-providers-in-angularjs/

Page 119: Advanced AngularJS

Testing Links

http://tryjasmine.com/

http://www.summa-tech.com/blog/2014/05/19/a-beginners-guide-to-angular-unit-tests

http://jasmine.github.io/2.0/introduction.html

http://andyshora.com/unit-testing-best-practices-angularjs.html

Page 120: Advanced AngularJS

Misc. Links

http://ablogaboutcode.com/2011/06/14/how-javascript-loading-works-domcontentloaded-and-onload/

http://garann.github.io/template-chooser/