Download pptx - AngularJS in practice

Transcript
Page 1: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Jon HoguetSr. UI [email protected]

AngularJS in Practice

Page 2: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Jon Hoguet who?

Page 3: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

▪ Our Architecture▪ Overview▪ Metrics▪ File Structure▪ Lessons Learned

▪ Angular ▪ Controller▪ Directive▪ $compile▪ Directives and Isolate Scope▪ Lessons Learned

▪ Build▪ Grunt▪ Testing with Karma▪ Testing with Protractor

▪ Debugging▪ $log▪ in the browser

▪ I reading this online, you should check out the ▪ Correlating Blog Post

What to expect

Page 4: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Our Architecture

Page 5: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

15 Angular Modules

43 Angular Directives

15 Angular Controllers

36 Angular Services

52 Angular Templates

13,669 lines of javascript

Focusing on Angular

Page 6: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Some Humility

Page 7: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

File Structure

Page 8: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Minimal Grails dependency

Page 9: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Do organize around functionality

Build First

Don’t mix templating languages

Lessons Learned

Page 10: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Don’t mix templating languages

<inventory:firedoor firedoorClass="search-firedoor lifecycle-criteria"

ngshow="lifecycles.targetLifecycle.isEditingCriteria" fluid="false"

customButtons="${[ [click:

'lifecycles.targetLifecycle.isEditingCriteria=false', icon: 'check', text: 'Done', customClass:

'btn-primary'] ]}">

<div class="form-group lifecycle-name-group">

<input type="text" class="form-control input-lg"

ng-model="lifecycles.targetLifecycle.model.name"

ng-change="lifecycles.targetLifecycle.dirty()"

placeholder="Enter a name...">

</div><div criteria-form title="Lifecycle Criteria"

criteria-model="lifecycles.targetLifecycle.model.criteria"

dirty="lifecycles.targetLifecycle.dirty">

</div>

</inventory:firedoor>

Page 11: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Controllers vs Directives

Page 12: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

A controller is an abstraction of

a directive

Page 13: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Consider...

Page 14: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Controller right?

Page 15: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Somewhere else in the dom...

Page 16: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Controller abstraction of directive isn’t working… use a directive

Page 17: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Page 18: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

$compile = BFF

$compile( markup / directives )( scope ) = live dom

fragment

1. Most important thing angular does2. composable3. makes testing easy4. makes experimentation easy

Page 19: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

live dom element

var ioc = angular.element('[ng-app]').injector(),

$rootScope = ioc.get('$rootScope'),

$compile = ioc.get('$compile');

var scope = $rootScope.$new(true);

scope.child = {

name : 'Lance',

age : 3

};

var markup = "<div>{{ child.name }} is {{ child.age }} years old!</div>";

var el;

scope.$apply(function(){

el = $compile(markup)(scope);

});

// el.html() === 'Lance is 3 years old!'

Page 20: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

live dom element

var ioc = angular.element('[ng-app]').injector(),

$rootScope = ioc.get('$rootScope'),

$compile = ioc.get('$compile');

var scope = $rootScope.$new(true);

scope.child = {

name : 'Lance',

age : 3

};

var markup = "<div>{{ child.name }} is {{ child.age }} years old!</div>";

var el;

scope.$apply(function(){

el = $compile(markup)(scope);

});

// el.html() === 'Lance is 3 years old!'

Page 21: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

live dom element

var ioc = angular.element('[ng-app]').injector(),

$rootScope = ioc.get('$rootScope'),

$compile = ioc.get('$compile');

var scope = $rootScope.$new(true);

scope.child = {

name : 'Lance',

age : 3

};

var markup = "<div>{{ child.name }} is {{ child.age }} years old!</div>";

var el;

scope.$apply(function(){

el = $compile(markup)(scope);

});

// el.html() === 'Lance is 3 years old!'

Page 22: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

live dom element

var ioc = angular.element('[ng-app]').injector(),

$rootScope = ioc.get('$rootScope'),

$compile = ioc.get('$compile');

var scope = $rootScope.$new(true);

scope.child = {

name : 'Lance',

age : 3

};

var markup = "<div>{{ child.name }} is {{ child.age }} years old!</div>";

var el;

scope.$apply(function(){

el = $compile(markup)(scope);

});

// el.html() === 'Lance is 3 years old!'

Page 23: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

live dom element

var ioc = angular.element('[ng-app]').injector(),

$rootScope = ioc.get('$rootScope'),

$compile = ioc.get('$compile');

var scope = $rootScope.$new(true);

scope.child = {

name : 'Lance',

age : 3

};

var markup = "<div>{{ child.name }} is {{ child.age }} years old!</div>";

var el;

scope.$apply(function(){

el = $compile(markup)(scope);

});

// el.html() === 'Lance is 3 years old!'

Page 24: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

live dom element

var ioc = angular.element('[ng-app]').injector(),

$rootScope = ioc.get('$rootScope'),

$compile = ioc.get('$compile');

var scope = $rootScope.$new(true);

scope.child = {

name : 'Lance',

age : 3

};

var markup = "<div>{{ child.name }} is {{ child.age }} years old!</div>";

var el;

scope.$apply(function(){

el = $compile(markup)(scope);

});

// el.html() === 'Lance is 3 years old!'

Page 25: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

What do you mean live?

scope.$apply(function(){

scope.child = {

name : 'Lana',

age : 2

};

});

//el.html() === 'Lana is 2 years old!'

Page 26: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Live meaning 2 way

markup = "<input type=\"text\" ng-model=\"child.name\" />";

var input;

// note we are applying the same scope to this markup

scope.$apply(function(){

input = $compile(markup)(scope);

});

input.val('Lana Hoguet');

input.change();

// scope.name === 'Lana Hoguet'

// el.html() === 'Lana Hoguet is 2 years old!'

Page 27: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Live meaning 2 way

markup = "<input type=\"text\" ng-model=\"child.name\" />";

var input;

// note we are applying the same scope to this markup

scope.$apply(function(){

input = $compile(markup)(scope);

});

input.val('Lana Hoguet');

input.change();

// scope.name === 'Lana Hoguet'

// el.html() === 'Lana Hoguet is 2 years old!'

Page 28: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Live meaning 2 way

markup = "<input type=\"text\" ng-model=\"child.name\" />";

var input;

// note we are applying the same scope to this markup

scope.$apply(function(){

input = $compile(markup)(scope);

});

input.val('Lana Hoguet');

input.change();

// scope.child.name === 'Lana Hoguet'

// el.html() === 'Lana Hoguet is 2 years old!'

Page 29: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Live meaning 2 way

markup = "<input type=\"text\" ng-model=\"child.name\" />";

var input;

// note we are applying the same scope to this markup

scope.$apply(function(){

input = $compile(markup)(scope);

});

input.val('Lana Hoguet');

input.change();

// scope.child.name === 'Lana Hoguet'

// el.html() === 'Lana Hoguet is 2 years old!'

Page 30: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Hurt yet?

Page 31: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Directives Refresher

Page 32: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Directives Refresher

= for two way

@ for one way

& for functions

Page 33: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

one way / two way misnomer

Page 34: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

one way / two way misnomer$compile source code

Page 35: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

one way / two way misnomer$compile source code

Page 36: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

one way / two way misnomer

Note: $interpolate and $parse are not coupled to $scope

Page 37: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

= for two way uses $parse

@ for one way uses $interpolate

& for functions

Page 38: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

& demystified

Page 39: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

& demystified

$compile source code

Page 40: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

= for two way uses $parse

@ for one way uses $interpolate

& for functions wraps $parse in fn

Page 41: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

= for two way uses $parse and watches

@ for one way uses $interpolate and watches

& for functions wraps $parse in fn

Page 42: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Page 43: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Beware the ng-model monster

fiddle

Page 44: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Page 45: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Page 46: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

angular-templates

Not proposing you use inline scripts - just simple example

Page 47: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

angular-templates

$templateCache

$http

Not proposing you use inline scripts - just simple example

Page 48: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

angular-templates

ng-include, ng-view, ui-view, or templateUrl

$http $templateCache

Page 49: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

angular-templates

npm install grunt-angular-templates --save-dev

Page 50: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

angular-templates

Page 51: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

angular-modules

Page 52: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

angular-modules

Page 53: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Page 54: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Unit testing directives is easy!

Page 55: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Protractor

Not Just for Angular

But has angular specific hooks built in

Promises!!

Page 56: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Debugging - Log More

Page 57: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Debugging - In the Browser

You can get anything out of IOC

Page 58: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Debugging - In the Browser

You can inspect any scope

Page 59: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Debugging - In the Browser

You can mutate the scope and verify how the view reacts

Page 60: AngularJS in practice

©2014 Dealertrack, Inc. All rights reserved.

Conclusion