Slide 1

Slide 1 text

Angular Migration Workshop Manfred Steyer ManfredSteyer

Slide 2

Slide 2 text

About me … • Manfred Steyer • SOFTWAREarchitekt.at • Trainer & Consultant • Google Developer Expert • Focus: Angular Page  2 Manfred Steyer

Slide 3

Slide 3 text

Goals • Find out how to prepare for a migration to Angular 2 • Find out how to migrate to Angular 2 step by step

Slide 4

Slide 4 text

Contents • General Approaches for Migrating to Angular 2 • Preparation • Controller-as • Components in AngularJS 1.5+ • One Way Binding • Communication between Components in AngularJS 1.5+ • Routing to Components • TypeScript and AngularJS 1.x • Webpack • Migrating to Angular 2 with ngUpgrade • Demonstration without Exercises • Exercises

Slide 5

Slide 5 text

Sample Application

Slide 6

Slide 6 text

General Approaches Page  6

Slide 7

Slide 7 text

Ostrich-Strategy Page  7 [https://creativecommons.org/licenses/by/2.0/] [(c) weisserstier, 110613_Straussenland 089, http://tinyurl.com/jza7wcy]

Slide 8

Slide 8 text

Microservice Approach Page  8 Module 1 AngularJS 1.x Module 2 Angular 2 Module 3 Angular 2

Slide 9

Slide 9 text

Page  9 FlightCard FlightSvc FlightList App 1 1 1 1 Migrating step by step with ngUpgrade

Slide 10

Slide 10 text

Migrating step by step with ngUpgrade Page  10 FlightCard FlightSvc FlightList App 1 1 2 2

Slide 11

Slide 11 text

Migrating step by step with ngUpgrade Page  11 FlightCard FlightSvc PassengerCard PassengerSvc FlightList PassengerList App 1 1 1 1 2 2 2

Slide 12

Slide 12 text

Migrating step by step with ngUpgrade Page  12 FlightCard FlightSvc PassengerCard PassengerSvc FlightList PassengerList App 2 2 2 2 2 2 2

Slide 13

Slide 13 text

Two Steps Preparation Migration Page  13

Slide 14

Slide 14 text

Preparation Page  14

Slide 15

Slide 15 text

Components in Angular 2 Page  15 Component Controller Template

Slide 16

Slide 16 text

Components in Angular 2 Page  16 Component Controller Template controller new

Slide 17

Slide 17 text

Application as a Component-Tree Page  17

Slide 18

Slide 18 text

Why components? • Break down complexity • Reusable units • Testable units

Slide 19

Slide 19 text

Controller in AngularJS 1.x Page  19 Controller Template Scope x y z

Slide 20

Slide 20 text

Controller in AngularJS 1.x Page  20 Controller Template Scope vm

Slide 21

Slide 21 text

Controller-as Page  21 Controller Template Scope myCtrl
[…]
new

Slide 22

Slide 22 text

Controller-as Page  22 Controller Template Scope myCtrl
[…]
new

Slide 23

Slide 23 text

Constructor-Function for Controller Page  23 function FlightListController($http, $log) { this.from = "Graz"; this.to = "Hamburg"; this.selectedFlight = null; this.flights = []; this.message = ""; this.search = function() { … } this.select = function() { … } }

Slide 24

Slide 24 text

Controller-as and UI-Router Page  24 $stateProvider.state('home', { url: '/home', templateUrl: '/app/home/home.html', controller: 'home', controllerAs: 'home' })

Slide 25

Slide 25 text

Controller-as and Directives Page  25 app.directive('passengerCard', function() { return { restrict: 'E', templateUrl: '…', controller: function() { this.select = function() { this.selectedItem = this.item; } }, controllerAs: 'myCtrl', scope: { item: '=', selectedItem: '=' }, bindToController: true } });

Slide 26

Slide 26 text

Controller-as and Directives Page  26 app.directive('passengerCard', function() { return { restrict: 'E', templateUrl: '…', controller: function() { this.select = function() { this.selectedItem = this.item; } }, controllerAs: 'myCtrl', bindToController: { item: '=', selectedItem: '=' } } });

Slide 27

Slide 27 text

Components in Angular 1.5 Page  27 app.component('passengerCard', { templateUrl: '[…]', controller: function() { this.select = function() { this.selectedItem = this.item; } }, controllerAs: 'myCtrl', // <-- Default: $ctrl bindings: { item: '=', selectedItem: '=' } });

Slide 28

Slide 28 text

Components in ng1.5 Page  28 restrict: 'E' scope: {} bindToController controllerAs (Default $ctrl) No compile No link No replace

Slide 29

Slide 29 text

Why components in AngularJS 1.5+ • Alignment to Angular 2 • Components can be migrated to Angular 2 one by one

Slide 30

Slide 30 text

One Way Binding Page  30

Slide 31

Slide 31 text

Data Binding in Angular 1.x Page  31 Model Model Directive Nearly everything can depend on everything Solution: Multiple Digest-Cycles

Slide 32

Slide 32 text

Component Tree in Angular 2 Page  32 Component for whole App Component (e. g. list) Component (e. g. list-item) Component (e. g. list-item)

Slide 33

Slide 33 text

Rules for Property Bindings • A Component only depends on its own data (and indirectly on its parent‘s data) • A Component must not depend on its childrens‘ data! • Dependency Graph is a tree • Angular only needs one digest cycle to update tree Page  33

Slide 34

Slide 34 text

Property Binding Page  34 model item item {{ item.title }} {{ item.title }} [http://victorsavkin.com/post/110170125256/change-detection-in-angular-2]

Slide 35

Slide 35 text

Event Bindings (One Way, Bottom/Up) Page  35 {{ item.title }} {{ item.title }} Event-Handler Event-Handler

Slide 36

Slide 36 text

Event Bindings (One Way, Bottom/Up) • No digest cycles for propagating events • But: Events can change state  Property Bindings Page  36

Slide 37

Slide 37 text

Property and Event Bindings Page  37 Performing Property Bindings Executing Event Handlers Event occurs App is ready All handlers executed Properties bound

Slide 38

Slide 38 text

Two Way Binding in Angular 2 • Combination of Property- and Event-Binding • For instance: ngModel and ngModelChange • Good performance because of unidirectional data flow • Syntactical Sugar:

Slide 39

Slide 39 text

passenger-card

Slide 40

Slide 40 text

passenger-card Page  40 passenger-card item selectedItem > > > selectedItemChange passenger selectedPassenger

Slide 41

Slide 41 text

One Way Bindings Page  41 app.component('passengerCard', { templateUrl: '[…]', controller: function() { this.select = function() { this.selectedItem = this.item; this.selectedItemChange(this.item); } }, controllerAs: 'myCtrl', // <-- Default: $ctrl bindings: { item: '<', selectedItem: '<', selectedItemChange: '&' } });

Slide 42

Slide 42 text

Less Watchers == Better Performance

Slide 43

Slide 43 text

Life Cycle Hooks Page  43 $onInit $onChanges $onDestroy $postLink Only for one way bindings (< und @)

Slide 44

Slide 44 text

Communication between Components

Slide 45

Slide 45 text

Application as a Component-Tree Page  45 Tabs Tab Tab

Slide 46

Slide 46 text

Tabs and Tab Tabs Tab

Slide 47

Slide 47 text

Tab Component app.component('tab', { require: { tabs: '^tabs' }, controller: function() { this.$onInit = function() { this.tabs.register(this); } }, bindings: { title: '@' }, transclude: true, template: '[...]' });

Slide 48

Slide 48 text

Tabs Component app.component('tabs', { controller: function() { this.tabs = []; this.register = function(tab) { this.tabs.push(tab); } this.activate = function(tab) {…} this.$postLink = function() { if (this.tabs.length == 0) return; this.activate(this.tabs[0]); } } […] });

Slide 49

Slide 49 text

Routing to Components Page  49

Slide 50

Slide 50 text

Components and UI-Router 0.x Page  50 $stateProvider.state('passenger-list', { url: '/passenger-list', template: '' });

Slide 51

Slide 51 text

TypeScript Page  51

Slide 52

Slide 52 text

TypeScript ES 6 ES 5 < ES 6 < TypeScript Page  52 ES 5

Slide 53

Slide 53 text

Controller in TypeScript Page  53 export class FlightSearchController { public from: string; public to: string; constructor() { this.from = "Vienna"; this.to = "London"; } public search() { […] } public select() { […] } }

Slide 54

Slide 54 text

Using TypeScript TypeScript-Compiler compiles TypeScript down to ES6, ES5 oder ES3 Page  55

Slide 55

Slide 55 text

tsconfig.json { "compilerOptions": { "target": "es5", "module": "commonjs", "moduleResolution": "node" "outDir": "dist/ts", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, }, "exclude": [ "node_modules" "dist" ] }

Slide 56

Slide 56 text

Typings • Files that define types for JavaScript libraries • TypeScript uses them to work with preexisting JavaScript code • Huge repository: http://definitelytyped.org/ • typings install angular • npm install @types/angular

Slide 57

Slide 57 text

Webpack Page  58 File A File B File C File D File E Entry Point Bundle Bundle Loader (z.B. .ts  .js)

Slide 58

Slide 58 text

Why webpack • Works declarative and not imperative • Aligns to NodeJS convetions • Fast solution • Huge community

Slide 59

Slide 59 text

webpack.config.js […] devtool: 'source-map', entry: { 'vendor': './app/vendor.ts', 'app': './app/app.ts' }, […]

Slide 60

Slide 60 text

webpack.config.js […] module: { loaders: [ […] { test: /\.ts$/, loaders: [ 'angular2-template-loader', 'awesome-typescript-loader‚ ] } ] }, […]

Slide 61

Slide 61 text

Migrating to Angular 2 Page  62

Slide 62

Slide 62 text

ngUpgrade Page  63 FlightCard FlightSvc PassengerCard PassengerSvc FlightList PassengerList App 1 1 1 1 2 2 2

Slide 63

Slide 63 text

What do we need? • AngularJS 1.x • Angular 2 (+ upgrade.js) Page  64

Slide 64

Slide 64 text

Using ngUpgrade var app = angular.module('flight-app', [...]); [...]

Slide 65

Slide 65 text

Using ngUpgrade var app = angular.module('flight-app', [...]); [...] const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule));

Slide 66

Slide 66 text

Using ngUpgrade var app = angular.module('flight-app', [...]); [...] const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); @NgModule({ imports: [ ... ], declarations: [ ... ], providers: [ ... ] }) class AppModule { }

Slide 67

Slide 67 text

Using ngUpgrade var app = angular.module('flight-app', [...]); [...] const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); @NgModule({ imports: [ ... ], declarations: [ ... ], providers: [ ... ] }) class AppModule { } // Upgrade ng1 services and providers // Downgrade ng2 services and providers

Slide 68

Slide 68 text

Using ngUpgrade var app = angular.module('flight-app', [...]); [...] const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); @NgModule({ imports: [ ... ], declarations: [ ... ], providers: [ ... ] }) class AppModule { } // Upgrade ng1 services and providers // Downgrade ng2 services and providers upgradeAdapter.bootstrap(document.body, ['flight-app']);

Slide 69

Slide 69 text

UpgradeAdapter Page  70 upgradeNg1 Component upgradeNg1 Provider downgradeNg2 Component downgradeNg2 Provider

Slide 70

Slide 70 text

Angular 2 in a Nutshell

Slide 71

Slide 71 text

Component Controller Page  72 @Component({ selector: 'flight-sarch', templateUrl: 'flight-search.html' }) export class FlightSearchComponent { from: string; to: string; flights: Array; constructor(http: Http) { } search() { [...] } select(flug: Flight) { [...] } }

Slide 72

Slide 72 text

Template Page  73 Search {{flug.id}} {{flug.datum}} {{flug.von}} {{flug.nach}}

Slide 73

Slide 73 text

Service Page  74 @Injectable() export class FlightService { […] }

Slide 74

Slide 74 text

AppModule Page  75 @NgModule({ imports: [ BrowserModule, HttpModule, FormsModule ], declarations: [ AppComponent, FlightSearchComponent ], providers: [ FlightService ], bootstrap: [ AppComponent ] }) export class AppModule { }

Slide 75

Slide 75 text

DEMO

Slide 76

Slide 76 text

Exercise

Slide 77

Slide 77 text

Your turn • Labs (Step-by-Step): https://goo.gl/vCEdBy • If there are any questions, feel free to ask. • Solution: https://goo.gl/RRYGrF • Slides: https://goo.gl/oC6jBn Contact [mail] [email protected] [blog] SOFTWAREarchitekt.at [twitter] ManfredSteyer

Slide 78

Slide 78 text

Contact [mail] [email protected] [blog] SOFTWAREarchitekt.at [twitter] ManfredSteyer